home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Devices and Hardware / Velocity Engine / VelEng FFT / vBigDSP / vBigDSP.c next >
Encoding:
Text File  |  2000-09-28  |  287.3 KB  |  7,649 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        vBigDSP.c
  3.  
  4.     Contains:    AltiVec-based Implementation of DSP routines (real & complex FFT, convolution)
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.                 10/12/99    JK        Created
  13.  
  14. */
  15.  
  16. /////////////////////////////////////////////////////////////////////////////////
  17. //      File Name: vBigDSP.c                                                   //
  18. //                                                                               //
  19. //        This library provides a set of DSP routines, implemented using the       //
  20. //        AltiVec instruction set.                                                 //
  21. //                                                                               //
  22. //                                                                             //
  23. //      Copyright © 1999 Apple Computer, Inc.  All rights reserved.            //
  24. //                                                                             //
  25. //      Version 1.0                                                            //
  26. //                                                                             //                                                                             //
  27. /////////////////////////////////////////////////////////////////////////////////
  28.  
  29. /*
  30.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  31.                 ("Apple") in consideration of your agreement to the following terms, and your
  32.                 use, installation, modification or redistribution of this Apple software
  33.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  34.                 please do not use, install, modify or redistribute this Apple software.
  35.  
  36.                 In consideration of your agreement to abide by the following terms, and subject
  37.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  38.                 copyrights in this original Apple software (the "Apple Software"), to use,
  39.                 reproduce, modify and redistribute the Apple Software, with or without
  40.                 modifications, in source and/or binary forms; provided that if you redistribute
  41.                 the Apple Software in its entirety and without modifications, you must retain
  42.                 this notice and the following text and disclaimers in all such redistributions of
  43.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  44.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  45.                 Apple Software without specific prior written permission from Apple.  Except as
  46.                 expressly stated in this notice, no other rights or licenses, express or implied,
  47.                 are granted by Apple herein, including but not limited to any patent rights that
  48.                 may be infringed by your derivative works or by other works in which the Apple
  49.                 Software may be incorporated.
  50.  
  51.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  52.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  53.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  54.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  55.                 COMBINATION WITH YOUR PRODUCTS.
  56.  
  57.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  58.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  59.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  60.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  61.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  62.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  63.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  64. */
  65.  
  66.  
  67.  
  68. #ifdef __MWERKS__
  69. #include <AltiVec.h>
  70. #endif
  71.  
  72. #include <errors.h>
  73. #include <math.h>
  74. #include <MacMemory.h>
  75.  
  76. #include "vBigDSP.h"
  77.  
  78. #ifndef PI
  79. #define PI (3.1415926535897932384626433832795)
  80. #endif
  81.  
  82.  
  83. ////////////////////////////////////////////////////////////////////////////////
  84. //    temporary workspace buffer for FFT implementations 
  85. ////////////////////////////////////////////////////////////////////////////////
  86. static Handle                gTempBufferHandle=nil;
  87.  
  88. ////////////////////////////////////////////////////////////////////////////////
  89. //    current buffer length for above handle
  90. ////////////////////////////////////////////////////////////////////////////////
  91. static unsigned long        gTempBufferSize = 0;
  92.  
  93. ////////////////////////////////////////////////////////////////////////////////
  94. //    table of pre-calculated sin & cos values for use by ping pong FFT
  95. ////////////////////////////////////////////////////////////////////////////////
  96. static Handle                 gSinCosTableHandle = nil;
  97.  
  98. ////////////////////////////////////////////////////////////////////////////////
  99. //    length of currently allocated sin & cos table
  100. ////////////////////////////////////////////////////////////////////////////////
  101. static unsigned long         gSinCosTableSize = 0;
  102.  
  103. ////////////////////////////////////////////////////////////////////////////////
  104. //
  105. //    log2max
  106. //
  107. //    This function computes the ceiling of log2(n).  For example:
  108. //
  109. //    log2max(7) = 3
  110. //    log2max(8) = 3
  111. //    log2max(9) = 4
  112. //
  113. ////////////////////////////////////////////////////////////////////////////////
  114. static long log2max(long     n)
  115. {
  116.     long     power = 1;
  117.     long    k = 1;
  118.  
  119.     if (n==1) {
  120.         return 0;
  121.     }
  122.     
  123.     while ((k <<= 1) < n) {
  124.         power++;
  125.     }
  126.     
  127.     return power;
  128. }
  129.  
  130.  
  131. ////////////////////////////////////////////////////////////////////////////////
  132. //
  133. //    EnsureStaticBufferSize
  134. //
  135. // This function is used to ensure that the global Handle gTempBufferHandle
  136. // is large enough to hold complexCount complex floats.  It compares the
  137. // currently allocated length (if there is one) with the desired length,
  138. // and, if necessary, allocates a new, larger handle.
  139. // It will NOT shrink the handle, because a function higher in the calling
  140. // chain may need the larger size.
  141. ////////////////////////////////////////////////////////////////////////////////
  142. static OSErr EnsureStaticBufferSize(long    complexCount)
  143. {
  144.     OSErr        result = noErr;
  145.     
  146.     if (gTempBufferSize < complexCount) {
  147.         
  148.         gTempBufferSize = complexCount;
  149.     
  150.         if (gTempBufferHandle) {
  151.             DisposeHandle(gTempBufferHandle);
  152.             gTempBufferHandle = nil;
  153.         }
  154.         
  155.         gTempBufferHandle = NewHandle(2*complexCount*sizeof(float));
  156.         
  157.         result = MemError();
  158.         
  159.         if (result != noErr) {
  160.             gTempBufferHandle = nil;
  161.             gTempBufferSize = 0;
  162.         }
  163.     }
  164.     
  165.     return result;
  166. }
  167.  
  168.  
  169. ///////////////////////////////////////////////////////////////////////////////////////////////
  170. // InitFFTSinCos
  171. //    Initialize cos & sin lookup table.
  172. ///////////////////////////////////////////////////////////////////////////////////////////////
  173. static OSErr InitFFTSinCos(long len) {
  174.     OSErr            result;
  175.     long             i;
  176.     float             angle;
  177.     float            *sinCosTable;
  178.     float            curSin;
  179.     float            curCos;
  180.     long            handleSize;
  181.     
  182.     ////////////////////////////////////////////////////////////////////////////////
  183.     // set length indicator to new length
  184.     ////////////////////////////////////////////////////////////////////////////////
  185.     gSinCosTableSize = len;
  186.     
  187.     ////////////////////////////////////////////////////////////////////////////////
  188.     // deallocate old handle if there is one
  189.     ////////////////////////////////////////////////////////////////////////////////
  190.     if(gSinCosTableHandle) DisposeHandle(gSinCosTableHandle);
  191.     
  192.     ////////////////////////////////////////////////////////////////////////////////
  193.     // calculate appropriate handle size for table.  Ensure a minimum length for
  194.     //  a one-entry (two-value: cos & sin) table
  195.     ////////////////////////////////////////////////////////////////////////////////
  196.     handleSize = sizeof(float) * len;
  197.     
  198.     if (!handleSize)    handleSize = 2 * sizeof(float);
  199.     
  200.     ////////////////////////////////////////////////////////////////////////////////
  201.     // alloc new handle for sin & cos table
  202.     ////////////////////////////////////////////////////////////////////////////////
  203.     gSinCosTableHandle = NewHandle(handleSize);
  204.  
  205.     result = MemError();
  206.     
  207.     if (result == noErr) {
  208.     
  209.         HLock(gSinCosTableHandle);
  210.  
  211.         ////////////////////////////////////////////////////////////////////////////////
  212.         // get pointer to start of sin cos table
  213.         // to reference as array
  214.         ////////////////////////////////////////////////////////////////////////////////
  215.         sinCosTable = *(float**)gSinCosTableHandle;
  216.  
  217.         if (len < 4) {
  218.             
  219.             ////////////////////////////////////////////////////////////////////////////////
  220.             // always create first entries in table
  221.             ////////////////////////////////////////////////////////////////////////////////            
  222.             sinCosTable[0] = 1;
  223.             sinCosTable[1] = 0;
  224.             
  225.             ////////////////////////////////////////////////////////////////////////////////
  226.             // if len is 2, then add second pair to table
  227.             ////////////////////////////////////////////////////////////////////////////////
  228.             if (len == 2) {
  229.                 sinCosTable[2] = -1;
  230.                 sinCosTable[3] = 0;
  231.             }
  232.                 
  233.         } else {
  234.     
  235.             ////////////////////////////////////////////////////////////////////////////////
  236.             // calculate cos & sin for range of 
  237.             // [0, pi].
  238.             ////////////////////////////////////////////////////////////////////////////////
  239.             for(i=0; i < len/4; i++) {
  240.                 angle = 2.0 * PI * i/len;
  241.  
  242.                 curCos = cos(angle);
  243.                 curSin = sin(angle);
  244.                 
  245.                 sinCosTable[2*i] = curCos;
  246.                 sinCosTable[2*i+1] = curSin;
  247.                 
  248.                 sinCosTable[len/2 + 2*i] = -curSin;
  249.                 sinCosTable[len/2 + 2*i + 1] = curCos;
  250.             }
  251.         }
  252.         
  253.         HUnlock(gSinCosTableHandle);
  254.         
  255.     }
  256.  
  257.     
  258.     ////////////////////////////////////////////////////////////////////////////////
  259.     // if there was an error, then dealloc
  260.     // anything we allocated, and reset
  261.     // length indicator to zero.
  262.     ////////////////////////////////////////////////////////////////////////////////
  263.     if (result != noErr) {
  264.         if (gSinCosTableHandle != nil) {
  265.             DisposeHandle(gSinCosTableHandle);
  266.             gSinCosTableHandle = nil;
  267.         }        
  268.         
  269.         gSinCosTableSize = 0;
  270.     }
  271.  
  272.     return result;
  273.         
  274. }
  275.  
  276.  
  277. ///////////////////////////////////////////////////////////////////////////////////////////////
  278. // ShutdownFFT
  279. //
  280. // deallocates any memory curently allocated for fft buffers.
  281. ///////////////////////////////////////////////////////////////////////////////////////////////
  282. void ShutdownFFT()
  283. {
  284.     if (gSinCosTableHandle != nil) {
  285.         DisposeHandle(gSinCosTableHandle);
  286.         gSinCosTableHandle = nil;
  287.     }
  288.  
  289.     gSinCosTableSize = 0;        
  290.  
  291.     if (gTempBufferHandle != nil) {
  292.         DisposeHandle(gTempBufferHandle);
  293.         gTempBufferHandle = nil;    
  294.     }
  295.     
  296.     gTempBufferSize = 0;
  297.  
  298.  
  299.  
  300. }
  301.  
  302.  
  303.  
  304. #pragma mark -
  305. #pragma mark R E C U R S I V E   C O M P L E X
  306.  
  307. ////////////////////////////////////////////////////////////////////////////////
  308. //    SquareComplexTransposeVector performs a transpose on a square matrix of
  309. //     complex floats with side length of rowLength.  Data is assumed to be
  310. //    arranged lexicographically, i.e., with side length n:
  311. //
  312. //    re[0] im[0]    re[1] im[1] ... re[n-1] im[n-1]
  313. //    re[n] im[n]        ...            re[2n-1] im[2n-1]
  314. //    .
  315. //    .
  316. //    re[(n-1)*n] im[(n-1)*n]    ...    re[n^2-1] im[n^2-1]
  317. //    
  318. //    Data becomes:
  319. //
  320. //    re[0] im[0] re[n] im[n] re[2n] im[2n]...
  321. //    re[1] im[1] re[n+1] im[n+1] ...
  322. //    re[2] im[2]    ...
  323. //    .
  324. //    .
  325. //    .
  326. //    re[n-1] im[n-1]    ...        re[n^2-1] im[n^2-1]
  327. //
  328. //
  329. ////////////////////////////////////////////////////////////////////////////////
  330.  
  331. static void SquareComplexTransposeVector(float *data, long rowLength)
  332. {
  333.     long                    i, j;
  334.     vector float             *pInLeft1, *pInLeft2;
  335.     vector float             *pInTop1, *pInTop2;
  336.     vector float             vInLeft1, vInLeft2;
  337.     vector float             vInTop1, vInTop2;
  338.     vector float             vOutLeft1, vOutLeft2;
  339.     vector float             vOutTop1, vOutTop2;
  340.     vector unsigned char     vMergeHiPairPerm;
  341.     vector unsigned char     vMergeLoPairPerm;        
  342.  
  343.     ////////////////////////////////////////////////////////////////////////////////
  344.     // initialize a permute vector that, given input vectors:
  345.     //
  346.     //    X = x0 x1 x2 x3
  347.     //    Y = y0 y1 y2 y3
  348.     //
  349.     // will generate
  350.     //    Z = x0 x1 y0 y1
  351.     ////////////////////////////////////////////////////////////////////////////////
  352.     vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  353.  
  354.     ////////////////////////////////////////////////////////////////////////////////
  355.     // initialize a permute vector that, given input vectors:
  356.     //
  357.     //    X = x0 x1 x2 x3
  358.     //    Y = y0 y1 y2 y3
  359.     //
  360.     // will generate
  361.     //    Z = x2 x3 y2 y3
  362.     ////////////////////////////////////////////////////////////////////////////////
  363.     vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  364.  
  365.     for (i=0; i<(rowLength/2); i++) {
  366.         
  367.         ////////////////////////////////////////////////////////////////////////////////
  368.         // set pointers to point to the beginning of row 2i and 2i+1
  369.         ////////////////////////////////////////////////////////////////////////////////
  370.         pInLeft1 = ((vector float*)data) + i * rowLength;
  371.         pInLeft2 = pInLeft1 + rowLength / 2;
  372.         
  373.         ////////////////////////////////////////////////////////////////////////////////
  374.         // set pointers to point to the first elements of columns 2i and 2i+1
  375.         ////////////////////////////////////////////////////////////////////////////////
  376.         pInTop1 = ((vector float*)data) + i;
  377.         pInTop2 = pInTop1 + rowLength / 2;
  378.     
  379.     
  380.         for (j=0; j<i; j++) {
  381.     
  382.             ////////////////////////////////////////////////////////////////////////////////
  383.             // read in two vectors that contain a 2x2 square of matrix elements
  384.             // from the left side of the diagonal
  385.             ////////////////////////////////////////////////////////////////////////////////
  386.                     
  387.             vInLeft1 = *pInLeft1;
  388.             vInLeft2 = *pInLeft2;
  389.  
  390.             ////////////////////////////////////////////////////////////////////////////////
  391.             // read in two vectors that contain a 2x2 square of matrix elements
  392.             // from the top side of the diagonal
  393.             ////////////////////////////////////////////////////////////////////////////////
  394.  
  395.             vInTop1 = *pInTop1;
  396.             vInTop2 = *pInTop2;
  397.  
  398.             ////////////////////////////////////////////////////////////////////////////////
  399.             //     We now transpose our two 2x2 sub-matrices, and swap their positions.  The
  400.             // transpose is done with vector permute operations.
  401.             ////////////////////////////////////////////////////////////////////////////////
  402.             
  403.             vOutLeft1 = vec_perm(vInTop1, vInTop2, vMergeHiPairPerm);
  404.             vOutLeft2 = vec_perm(vInTop1, vInTop2, vMergeLoPairPerm);
  405.  
  406.             vOutTop1 = vec_perm(vInLeft1, vInLeft2, vMergeHiPairPerm);
  407.             vOutTop2 = vec_perm(vInLeft1, vInLeft2, vMergeLoPairPerm);
  408.  
  409.             ////////////////////////////////////////////////////////////////////////////////
  410.             // store the transposed matrices in their swapped positions
  411.             ////////////////////////////////////////////////////////////////////////////////
  412.                 
  413.             *pInLeft1 = vOutLeft1;
  414.             *pInLeft2 = vOutLeft2;
  415.  
  416.             *pInTop1 = vOutTop1;
  417.             *pInTop2 = vOutTop2;
  418.  
  419.             ////////////////////////////////////////////////////////////////////////////////
  420.             // advance pointers to next elements in the current columns & rows
  421.             ////////////////////////////////////////////////////////////////////////////////
  422.                         
  423.             pInLeft1 += 1;
  424.             pInLeft2 += 1;
  425.             
  426.             pInTop1 += rowLength;
  427.             pInTop2 += rowLength;
  428.             
  429.         }
  430.  
  431.         ////////////////////////////////////////////////////////////////////////////////
  432.         // when the above loop is finished, our input pointers point to the 2x2 sub-
  433.         // matrix that is on the diagonal of our matrix to be transposed.  We read in
  434.         // this sub-matrix into two vectors, transpose the sub-matrix (using vector
  435.         // transposes) and store the sub-matrix.
  436.         ////////////////////////////////////////////////////////////////////////////////
  437.         
  438.         vInLeft1 = *pInLeft1;
  439.         vInLeft2 = *pInLeft2;
  440.         
  441.         vOutLeft1 = vec_perm(vInLeft1, vInLeft2, vMergeHiPairPerm);
  442.         vOutLeft2 = vec_perm(vInLeft1, vInLeft2, vMergeLoPairPerm);
  443.  
  444.         *pInLeft1 = vOutLeft1;
  445.         *pInLeft2 = vOutLeft2;
  446.     }
  447. }
  448.  
  449. ////////////////////////////////////////////////////////////////////////////////
  450. //    SquareComplexTransposeTwist performs a transpose on a square matrix of
  451. //     complex floats with side length of rowLength.  Data is assumed to be
  452. //    arranged lexicographically, i.e., with side length n.
  453. //
  454. //
  455. //
  456. //    re[0] im[0]    re[1] im[1] ... re[n-1] im[n-1]
  457. //    re[n] im[n]        ...            re[2n-1] im[2n-1]
  458. //    .
  459. //    .
  460. //    re[(n-1)*n] im[(n-1)*n]    ...    re[n^2-1] im[n^2-1]
  461. //    
  462. //
  463. //    In addition to performing the transpose, each element X(j, k) is
  464. //     multiplied by the twist factor e^(+/- 2 pi i j k / (n^2) ). 
  465. //
  466. ////////////////////////////////////////////////////////////////////////////////
  467.  
  468. static void SquareComplexTransposeTwist(float *data, long sideLength, long isInverse)
  469. {
  470.     long                        i, j;
  471.     vector float             *pInLeft1, *pInLeft2;
  472.     vector float             *pInTop1, *pInTop2;
  473.     vector float             vInLeft1, vInLeft2;
  474.     vector float             vInTop1, vInTop2;
  475.     vector float             vOutLeft1, vOutLeft2;
  476.     vector float             vOutTop1, vOutTop2;
  477.     vector float            vTwistedTop1, vTwistedTop2;
  478.     vector float            vPermutedLeft1, vPermutedLeft2;
  479.     
  480.     vector unsigned char     vMergeHiPairPerm;
  481.     vector unsigned char     vMergeLoPairPerm;        
  482.     vector unsigned char    vSwappedPerm;
  483.  
  484.     vector float            vCosTwistA0;
  485.     vector float            vCosTwistA1;
  486.  
  487.     vector float            vCosTemp0, vCosTemp1;
  488.  
  489.     vector float            vSinTwistA0;
  490.     vector float            vSinTwistA1;
  491.  
  492.     vector float            vA;
  493.     vector float            vB;
  494.  
  495.     vector float            vTransition;
  496.     vector float            vSinSignMultiplier;
  497.     vector float            vZero = (vector float)(0);
  498.     
  499.     
  500.     double                    fTemp;
  501.     double                    baseAngle1;
  502.     double                    baseAngle2;
  503.  
  504.     double                    fSinBaseAngle1;
  505.     double                    fSinBaseAngle2;
  506.  
  507.     ////////////////////////////////////////////////////////////////////////////////
  508.     // initialize multiplier for sin vector, for whether we are multiplying
  509.     // by e^(2 pi i l m / (n^2) ) or e^(-2 pi i l m / (n^2) ).
  510.     ////////////////////////////////////////////////////////////////////////////////
  511.     
  512.     if (isInverse) {
  513.         vSinSignMultiplier = (vector float)(-1, 1, -1, 1);
  514.     } else {
  515.         vSinSignMultiplier = (vector float)(1, -1, 1, -1);    
  516.     }
  517.  
  518.     ////////////////////////////////////////////////////////////////////////////////
  519.     // initialize a permute vector that, given input vectors:
  520.     //
  521.     //    X = x0 x1 x2 x3
  522.     //    Y = y0 y1 y2 y3
  523.     //
  524.     // will generate
  525.     //    Z = x0 x1 y0 y1
  526.     ////////////////////////////////////////////////////////////////////////////////
  527.     vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  528.  
  529.     ////////////////////////////////////////////////////////////////////////////////
  530.     // initialize a permute vector that, given input vectors:
  531.     //
  532.     //    X = x0 x1 x2 x3
  533.     //    Y = y0 y1 y2 y3
  534.     //
  535.     // will generate
  536.     //    Z = x2 x3 y2 y3
  537.     ////////////////////////////////////////////////////////////////////////////////
  538.     vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  539.  
  540.     ////////////////////////////////////////////////////////////////////////////////
  541.     // initialize a permute vector that, given input vectors:
  542.     //
  543.     //    X = x0 x1 x2 x3
  544.     //    Y = y0 y1 y2 y3
  545.     //
  546.     // will generate
  547.     //    Z = x1 x0 x3 y2
  548.     ////////////////////////////////////////////////////////////////////////////////
  549.     vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  550.  
  551.  
  552.     ////////////////////////////////////////////////////////////////////////////////
  553.     //
  554.     // special-case upper-left 2x2 sub-matrix
  555.     //
  556.     ////////////////////////////////////////////////////////////////////////////////
  557.  
  558.     ////////////////////////////////////////////////////////////////////////////////
  559.     //    set pointers to point at first and second rows    
  560.     ////////////////////////////////////////////////////////////////////////////////
  561.  
  562.     pInLeft1 = ((vector float*)data);
  563.     pInLeft2 = pInLeft1 + sideLength / 2;
  564.  
  565.     ////////////////////////////////////////////////////////////////////////////////
  566.     //    create twist multiplier cos & sin vectors
  567.     //
  568.     //    the vTransition vector is used to move elements from the scalar domain
  569.     //     to the vector domain.
  570.     ////////////////////////////////////////////////////////////////////////////////
  571.     
  572.     baseAngle1 = 0;
  573.     baseAngle2 = (2*PI)/(sideLength*sideLength);
  574.  
  575.     fSinBaseAngle1 = sin(baseAngle1);
  576.     fSinBaseAngle2 = sin(baseAngle2);
  577.  
  578.     ((float*)&vTransition)[0] = 1;
  579.     
  580.     ((float*)&vTransition)[2] = cos(baseAngle1);
  581.     ((float*)&vTransition)[3] = cos(baseAngle2);
  582.     
  583.     vCosTwistA0 = vec_splat(vTransition, 0);
  584.     vCosTwistA1 = vec_mergel(vTransition, vTransition);
  585.     
  586.     vSinTwistA0 = vZero;
  587.     
  588.     ((float*)&vTransition)[2] = fSinBaseAngle1;
  589.     ((float*)&vTransition)[3] = fSinBaseAngle2;
  590.                             
  591.     vSinTwistA1 = vec_mergel(vTransition, vTransition);
  592.     vSinTwistA1 = vec_madd(vSinTwistA1, vSinSignMultiplier, vZero);
  593.  
  594.     ////////////////////////////////////////////////////////////////////////////////
  595.     // twist multiply & permute 2x2 square on diagonal.
  596.     ////////////////////////////////////////////////////////////////////////////////
  597.     
  598.     vInLeft1 = *pInLeft1;
  599.     vInLeft2 = *pInLeft2;
  600.                 
  601.     vPermutedLeft1 = vec_perm(vInLeft1, vInLeft2, vMergeHiPairPerm);
  602.     vPermutedLeft2 = vec_perm(vInLeft1, vInLeft2, vMergeLoPairPerm);
  603.     
  604.     vOutLeft1 = vec_madd(vPermutedLeft1, vCosTwistA0, vZero);
  605.     vOutLeft1 = vec_madd(vec_perm(vPermutedLeft1, vPermutedLeft1, vSwappedPerm), vSinTwistA0, vOutLeft1);
  606.  
  607.     vOutLeft2 = vec_madd(vPermutedLeft2, vCosTwistA1, vZero);
  608.     vOutLeft2 = vec_madd(vec_perm(vPermutedLeft2, vPermutedLeft2, vSwappedPerm), vSinTwistA1, vOutLeft2);
  609.  
  610.     *pInLeft1 = vOutLeft1;
  611.     *pInLeft2 = vOutLeft2;
  612.  
  613.     ////////////////////////////////////////////////////////////////////////////////
  614.     // loop through all remaining rows/columns 2 at a time
  615.     ////////////////////////////////////////////////////////////////////////////////
  616.  
  617.     for (i=1; i<(sideLength/2); i++) {
  618.  
  619.         ////////////////////////////////////////////////////////////////////////////////
  620.         // set pointers to point to the beginning of row 2i and 2i+1
  621.         ////////////////////////////////////////////////////////////////////////////////
  622.         pInLeft1 = ((vector float*)data) + i * sideLength;
  623.         pInLeft2 = pInLeft1 + sideLength / 2;
  624.         
  625.         ////////////////////////////////////////////////////////////////////////////////
  626.         // set pointers to point to the first elements of columns 2i and 2i+1
  627.         ////////////////////////////////////////////////////////////////////////////////
  628.         pInTop1 = ((vector float*)data) + i;
  629.         pInTop2 = pInTop1 + sideLength / 2;
  630.     
  631.         ////////////////////////////////////////////////////////////////////////////////
  632.         // set up vectors for incremental updating of cos & sin vectors
  633.         //
  634.         // Given c = cos(w) and s = sin(w), if we want to find the cos and sin of w plus
  635.         // some small angle d, then we can do so by defining:
  636.         //    
  637.         // a = 2 * ((sin(d/2)) ^ 2)
  638.         // b = sin(d)
  639.         // 
  640.         // Then, we can calculate the cos and sin of the updated angle w+d as:
  641.         // 
  642.         // cos(w+d) = c - ac - bs
  643.         // sin(w+d) = s - as + bc
  644.         // 
  645.         // the vectors vA and vB contain these increment factors a and b.  Note that
  646.         // each outer loop iteration requires different increment angles.  Looking at
  647.         // the matrix, the angle multipliers that we use for our cos & sin twist
  648.         // multipliers look something like:
  649.         //
  650.         //        0/N        0/N        0/N        0/N        0/N        0/N        0/N    ...    0/N
  651.         //        0/N        1/N        2/N        3/N        4/N        5/N        6/N        
  652.         //        0/N        2/N        4/N        6/N        8/N        10/N    12/N    .
  653.         //        0/N        3/N        6/N        9/N        12/N    15/N    18/N    .    
  654.         //        0/N        4/N        8/N        12/N    16/N    20/N    24/N
  655.         //        .        .
  656.         //        .        .
  657.         //        0/N                                            ...            (N-1)(N-1)
  658.         //
  659.         // Since we're doing two rows/columns at a time, the vA and vB vectors
  660.         // need to have two different sets of increment values.  For example, for
  661.         // the third and fourth columns (handled in the second time through the
  662.         // outer loop) each row increments by 2/N and 3/N.  Since we actually 
  663.         // have two sets of twist multiplier vectors, we skip a row for each, so
  664.         // the increment angle is doubled.  This helps reduce calculation dependencies
  665.         // and cuts the number of increment iterations in half, which helps reduce
  666.         // errors in the single-precision calculations used.
  667.         //        
  668.         ////////////////////////////////////////////////////////////////////////////////
  669.  
  670.         baseAngle1 = 4*i*PI/(sideLength*sideLength);
  671.         baseAngle2 = (2*(2*i+1)*PI)/(sideLength*sideLength);
  672.  
  673.         fSinBaseAngle1 = sin(baseAngle1);
  674.         fTemp = 2*fSinBaseAngle1*fSinBaseAngle1;
  675.         
  676.         ((float*)&vTransition)[0] = fTemp;
  677.         ((float*)&vTransition)[2] = sin(2*baseAngle1);
  678.  
  679.         fSinBaseAngle2 = sin(baseAngle2);
  680.         fTemp = 2*fSinBaseAngle2*fSinBaseAngle2;
  681.  
  682.         ((float*)&vTransition)[1] = fTemp;
  683.         ((float*)&vTransition)[3] = sin(2*baseAngle2);
  684.  
  685.         vA = vec_mergeh(vTransition, vTransition);
  686.         vB = vec_mergel(vTransition, vTransition);
  687.         
  688.         vB = vec_madd(vB, vSinSignMultiplier, vZero);
  689.  
  690.         ////////////////////////////////////////////////////////////////////////////////
  691.         //    Set up the initial twist multiplier vectors for the beginning of this
  692.         // row/column pair.  Values are calculated in the scalar domain, and then
  693.         // transferred to the vector domain via the vTransition vector.
  694.         ////////////////////////////////////////////////////////////////////////////////
  695.         
  696.         ((float*)&vTransition)[0] = 1;
  697.         
  698.         ((float*)&vTransition)[2] = cos(baseAngle1);
  699.         ((float*)&vTransition)[3] = cos(baseAngle2);
  700.         
  701.         vCosTwistA0 = vec_splat(vTransition, 0);
  702.         vCosTwistA1 = vec_mergel(vTransition, vTransition);
  703.         
  704.         vSinTwistA0 = vZero;
  705.         
  706.         ((float*)&vTransition)[2] = fSinBaseAngle1;
  707.         ((float*)&vTransition)[3] = fSinBaseAngle2;
  708.                                 
  709.         vSinTwistA1 = vec_mergel(vTransition, vTransition);
  710.         vSinTwistA1 = vec_madd(vSinTwistA1, vSinSignMultiplier, vZero);
  711.  
  712.         ////////////////////////////////////////////////////////////////////////////////
  713.         // load in the leftmost and topmost 2x2 matrices for our row/column pair
  714.         ////////////////////////////////////////////////////////////////////////////////
  715.  
  716.         vInLeft1 = *pInLeft1;
  717.         vInLeft2 = *pInLeft2;
  718.  
  719.         vInTop1 = *pInTop1;
  720.         vInTop2 = *pInTop2;
  721.  
  722.         ////////////////////////////////////////////////////////////////////////////////
  723.         // twist multiply in top vectors and use permute to transpose before storing
  724.         // to position in new row.
  725.         ////////////////////////////////////////////////////////////////////////////////
  726.         
  727.         vTwistedTop1 = vInTop1;
  728.         
  729.         vTwistedTop2 = vec_madd(vInTop2, vCosTwistA1, vZero);
  730.         vTwistedTop2 = vec_madd(vec_perm(vInTop2, vInTop2, vSwappedPerm), vSinTwistA1, vTwistedTop2);
  731.  
  732.         vOutLeft1 = vec_perm(vTwistedTop1, vTwistedTop2, vMergeHiPairPerm);
  733.         vOutLeft2 = vec_perm(vTwistedTop1, vTwistedTop2, vMergeLoPairPerm);
  734.  
  735.         ////////////////////////////////////////////////////////////////////////////////
  736.         // use permute to transpose 2x2 matrix from current row, and then twist
  737.         // multiply.
  738.         ////////////////////////////////////////////////////////////////////////////////
  739.         
  740.         vPermutedLeft1 = vec_perm(vInLeft1, vInLeft2, vMergeHiPairPerm);
  741.         vPermutedLeft2 = vec_perm(vInLeft1, vInLeft2, vMergeLoPairPerm);
  742.         
  743.         vOutTop1 = vPermutedLeft1;
  744.  
  745.         vOutTop2 = vec_madd(vPermutedLeft2, vCosTwistA1, vZero);
  746.         vOutTop2 = vec_madd(vec_perm(vPermutedLeft2, vPermutedLeft2, vSwappedPerm), vSinTwistA1, vOutTop2);
  747.  
  748.         ////////////////////////////////////////////////////////////////////////////////
  749.         // update sin & cos twist multiplier vectors
  750.         ////////////////////////////////////////////////////////////////////////////////
  751.  
  752.         vCosTemp0 = vec_nmsub(vCosTwistA0, vA, vCosTwistA0);
  753.         vCosTemp0 = vec_nmsub(vSinTwistA0, vB, vCosTemp0);
  754.  
  755.         vSinTwistA0 = vec_nmsub(vSinTwistA0, vA, vSinTwistA0);
  756.         vSinTwistA0 = vec_madd (vCosTwistA0, vB, vSinTwistA0);
  757.  
  758.         vCosTwistA0 = vCosTemp0;
  759.  
  760.         vCosTemp1 = vec_nmsub(vCosTwistA1, vA, vCosTwistA1);
  761.         vCosTemp1 = vec_nmsub(vSinTwistA1, vB, vCosTemp1);
  762.  
  763.         vSinTwistA1 = vec_nmsub(vSinTwistA1, vA, vSinTwistA1);
  764.         vSinTwistA1 = vec_madd (vCosTwistA1, vB, vSinTwistA1);
  765.  
  766.         vCosTwistA1 = vCosTemp1;
  767.  
  768.         ////////////////////////////////////////////////////////////////////////////////
  769.         // store twist multiplied and transposed matrices.
  770.         ////////////////////////////////////////////////////////////////////////////////
  771.             
  772.         *pInLeft1 = vOutLeft1;
  773.         *pInLeft2 = vOutLeft2;
  774.  
  775.         *pInTop1 = vOutTop1;
  776.         *pInTop2 = vOutTop2;
  777.         
  778.         ////////////////////////////////////////////////////////////////////////////////
  779.         // update pointers to move down in current columns and right in current rows
  780.         ////////////////////////////////////////////////////////////////////////////////
  781.         
  782.         pInLeft1 += 1;
  783.         pInLeft2 += 1;
  784.         
  785.         pInTop1 += sideLength;
  786.         pInTop2 += sideLength;
  787.  
  788.         ////////////////////////////////////////////////////////////////////////////////
  789.         // loop through remaining 2x2 sub-matrices in current row/column pair until
  790.         // we reach the diagonal of the matrix.        
  791.         ////////////////////////////////////////////////////////////////////////////////
  792.             
  793.         for (j=1; j<i; j++) {
  794.  
  795.             ////////////////////////////////////////////////////////////////////////////////
  796.             // load in 2x2 matrices for our row/column pair
  797.             ////////////////////////////////////////////////////////////////////////////////
  798.             
  799.             vInLeft1 = *pInLeft1;
  800.             vInLeft2 = *pInLeft2;
  801.  
  802.             vInTop1 = *pInTop1;
  803.             vInTop2 = *pInTop2;
  804.  
  805.  
  806.             ////////////////////////////////////////////////////////////////////////////////
  807.             // twist multiply in top vectors and use permute to transpose before storing
  808.             // to position in new row.
  809.             ////////////////////////////////////////////////////////////////////////////////
  810.             
  811.             
  812.             vTwistedTop1 = vec_madd(vInTop1, vCosTwistA0, vZero);
  813.             vTwistedTop1 = vec_madd(vec_perm(vInTop1, vInTop1, vSwappedPerm), vSinTwistA0, vTwistedTop1);
  814.             
  815.             vTwistedTop2 = vec_madd(vInTop2, vCosTwistA1, vZero);
  816.             vTwistedTop2 = vec_madd(vec_perm(vInTop2, vInTop2, vSwappedPerm), vSinTwistA1, vTwistedTop2);
  817.  
  818.             vOutLeft1 = vec_perm(vTwistedTop1, vTwistedTop2, vMergeHiPairPerm);
  819.             vOutLeft2 = vec_perm(vTwistedTop1, vTwistedTop2, vMergeLoPairPerm);
  820.  
  821.             ////////////////////////////////////////////////////////////////////////////////
  822.             // use permute to transpose 2x2 matrix from current row, and then twist
  823.             // multiply.
  824.             ////////////////////////////////////////////////////////////////////////////////
  825.             
  826.             vPermutedLeft1 = vec_perm(vInLeft1, vInLeft2, vMergeHiPairPerm);
  827.             vPermutedLeft2 = vec_perm(vInLeft1, vInLeft2, vMergeLoPairPerm);
  828.             
  829.             vOutTop1 = vec_madd(vPermutedLeft1, vCosTwistA0, vZero);
  830.             vOutTop1 = vec_madd(vec_perm(vPermutedLeft1, vPermutedLeft1, vSwappedPerm), vSinTwistA0, vOutTop1);
  831.  
  832.             vOutTop2 = vec_madd(vPermutedLeft2, vCosTwistA1, vZero);
  833.             vOutTop2 = vec_madd(vec_perm(vPermutedLeft2, vPermutedLeft2, vSwappedPerm), vSinTwistA1, vOutTop2);
  834.  
  835.             ////////////////////////////////////////////////////////////////////////////////
  836.             // update sin & cos twist multiplier vectors
  837.             ////////////////////////////////////////////////////////////////////////////////
  838.  
  839.             vCosTemp0 = vec_nmsub(vCosTwistA0, vA, vCosTwistA0);
  840.             vCosTemp0 = vec_nmsub(vSinTwistA0, vB, vCosTemp0);
  841.  
  842.             vSinTwistA0 = vec_nmsub(vSinTwistA0, vA, vSinTwistA0);
  843.             vSinTwistA0 = vec_madd (vCosTwistA0, vB, vSinTwistA0);
  844.  
  845.             vCosTwistA0 = vCosTemp0;
  846.  
  847.             vCosTemp1 = vec_nmsub(vCosTwistA1, vA, vCosTwistA1);
  848.             vCosTemp1 = vec_nmsub(vSinTwistA1, vB, vCosTemp1);
  849.  
  850.             vSinTwistA1 = vec_nmsub(vSinTwistA1, vA, vSinTwistA1);
  851.             vSinTwistA1 = vec_madd (vCosTwistA1, vB, vSinTwistA1);
  852.  
  853.             vCosTwistA1 = vCosTemp1;
  854.  
  855.             ////////////////////////////////////////////////////////////////////////////////
  856.             // store twist multiplied and transposed matrices.
  857.             ////////////////////////////////////////////////////////////////////////////////
  858.                 
  859.             *pInLeft1 = vOutLeft1;
  860.             *pInLeft2 = vOutLeft2;
  861.  
  862.             *pInTop1 = vOutTop1;
  863.             *pInTop2 = vOutTop2;
  864.  
  865.             ////////////////////////////////////////////////////////////////////////////////
  866.             // update pointers to move down in current columns and right in current rows
  867.             ////////////////////////////////////////////////////////////////////////////////
  868.             
  869.             pInLeft1 += 1;
  870.             pInLeft2 += 1;
  871.             
  872.             pInTop1 += sideLength;
  873.             pInTop2 += sideLength;
  874.             
  875.         }
  876.         
  877.         ////////////////////////////////////////////////////////////////////////////////
  878.         // At this point, the above loop has left the pointers at the 2x2 sub-matrix
  879.         // on the diagonal.  We read in this 2x2 matrix, transpose it, twist multiply
  880.         // it, and store it back.
  881.         ////////////////////////////////////////////////////////////////////////////////
  882.         
  883.         vInLeft1 = *pInLeft1;
  884.         vInLeft2 = *pInLeft2;
  885.                     
  886.         vPermutedLeft1 = vec_perm(vInLeft1, vInLeft2, vMergeHiPairPerm);
  887.         vPermutedLeft2 = vec_perm(vInLeft1, vInLeft2, vMergeLoPairPerm);
  888.         
  889.         vOutLeft1 = vec_madd(vPermutedLeft1, vCosTwistA0, vZero);
  890.         vOutLeft1 = vec_madd(vec_perm(vPermutedLeft1, vPermutedLeft1, vSwappedPerm), vSinTwistA0, vOutLeft1);
  891.  
  892.         vOutLeft2 = vec_madd(vPermutedLeft2, vCosTwistA1, vZero);
  893.         vOutLeft2 = vec_madd(vec_perm(vPermutedLeft2, vPermutedLeft2, vSwappedPerm), vSinTwistA1, vOutLeft2);
  894.  
  895.         *pInLeft1 = vOutLeft1;
  896.         *pInLeft2 = vOutLeft2;
  897.     }
  898. }
  899.  
  900. ////////////////////////////////////////////////////////////////////////////////
  901. //    fft_recursive
  902. //
  903. //    Performs a recursive (N/2 by 2) forward or inverse FFT on the
  904. // signal pointed to by pData. This is done in the following manner.  First, the
  905. // signal X is divided into two parts, namely X1 = X(0, N/2-1) and 
  906. // X2 = X(N/2, N-1). These two sub-signals are then turned into the sum and
  907. // difference, respectively, of these two signals. This is in effect an FFT
  908. // of length 2 performed between each pair of elements taken from X1 and X2.
  909. // This produces two new subsignals X1' and X2'.
  910. //
  911. // Next, a twist operation is performed on X2', where X2'(j) is multiplied
  912. // by e^(2 pi ij / N).
  913. //
  914. // Next, a length N/2 complex FFT is performed on each of X1' and X2', yielding
  915. // X1" and X2".
  916. //
  917. // Finally, the elements of X1" and X2" are merged, so that the resulting
  918. // length-N signal Y is given by:
  919. //
  920. //    Y = X1"(0) X2"(0) X1"(1) X2"(1) ... X1"(N/2-1) X2"(N/2-1)
  921. //
  922. //    This resulting signal Y is the FFT of the original signal X
  923. //
  924. ////////////////////////////////////////////////////////////////////////////////
  925. static OSErr fft_recursive(float *pData, unsigned long len, long isign)
  926. {
  927.     OSErr                        result;
  928.     long                        i;
  929.  
  930.     vector float                *pInLoBottom, *pInLoTop, *pInHiBottom, *pInHiTop;
  931.     vector float                *pOutLoBottom, *pOutLoTop, *pOutHiBottom, *pOutHiTop;
  932.  
  933.     vector float                vLoBottom, vLoTop, vHiBottom, vHiTop;
  934.     
  935.     vector float                vZero;
  936.     vector float                vSinLo;
  937.     vector float                vCosLo;
  938.  
  939.     vector float                vSinHi;
  940.     vector float                vCosHi;
  941.  
  942.     vector float                vFTransition;
  943.     vector float                vFNegTransition;
  944.  
  945.     double                        updateA;
  946.     double                        updateB;
  947.  
  948.     double                        newCos1;
  949.     double                        newCos2;
  950.     double                        newSin1;
  951.     double                        newSin2;
  952.  
  953.     double                        tempCos1;
  954.     double                        tempCos2;
  955.     
  956.     double                        startSinMul;
  957.  
  958.     vector unsigned char        vCosLoPerm;
  959.     vector unsigned char        vSinPerm;
  960.     vector unsigned char        vSwapPairPerm;
  961.     vector unsigned char        vMergeLoPairPerm;
  962.     vector unsigned char        vMergeHiPairPerm;
  963.     vector unsigned long        vHiPairSelect;
  964.     
  965.     vector float                vDiffBottom;
  966.     vector float                vDiffTop;    
  967.     
  968.     vector float                vOneHalf;
  969.     
  970.     vector float                vTwistBottom;
  971.     vector float                vTwistTop;
  972.     
  973.     vector float                vSwappedDiffBottom;
  974.     vector float                vSwappedDiffTop;
  975.     
  976.     ////////////////////////////////////////////////////////////////////////////////
  977.     // make sure that work buffer is large enough to hold half of entire data
  978.     // length for merge operation at end of routine.
  979.     ////////////////////////////////////////////////////////////////////////////////
  980.     result = EnsureStaticBufferSize(len/2);
  981.     
  982.     if (result == noErr) {
  983.         
  984.         ////////////////////////////////////////////////////////////////////////////////
  985.         // initialize a permute vector that, given input vectors:
  986.         //
  987.         //    X = x0 x1 x2 x3
  988.         //    Y = y0 y1 y2 y3
  989.         //
  990.         // will generate
  991.         //    Z = x1 x0 x3 x2
  992.         ////////////////////////////////////////////////////////////////////////////////
  993.         vSwapPairPerm    = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  994.  
  995.         ////////////////////////////////////////////////////////////////////////////////
  996.         // initialize a permute vector that, given input vectors:
  997.         //
  998.         //    X = x0 x1 x2 x3
  999.         //    Y = y0 y1 y2 y3
  1000.         //
  1001.         // will generate
  1002.         //    Z = x0 x0 y3 y3
  1003.         ////////////////////////////////////////////////////////////////////////////////
  1004.         vCosLoPerm        = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 28, 29, 30, 31, 28, 29, 30, 31);
  1005.  
  1006.         ////////////////////////////////////////////////////////////////////////////////
  1007.         // initialize a select vector that, given input vectors:
  1008.         //
  1009.         //    X = x0 x1 x2 x3
  1010.         //    Y = y0 y1 y2 y3
  1011.         //
  1012.         // will generate
  1013.         //    Z = x0 x1 y2 y3
  1014.         ////////////////////////////////////////////////////////////////////////////////
  1015.         vHiPairSelect    = (vector unsigned long)((vector signed long)(0, 0, -1, -1));
  1016.  
  1017.         if (isign == -1) {
  1018.             startSinMul = 1;
  1019.  
  1020.             ////////////////////////////////////////////////////////////////////////////////
  1021.             // initialize a permute vector that, given input vectors:
  1022.             //
  1023.             //    X = x0 x1 x2 x3
  1024.             //    Y = y0 y1 y2 y3
  1025.             //
  1026.             // will generate
  1027.             //    Z = x0 y0 x1 y1
  1028.             ////////////////////////////////////////////////////////////////////////////////
  1029.             vSinPerm = (vector unsigned char)(0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23);
  1030.         } else {
  1031.             startSinMul = -1;
  1032.  
  1033.             ////////////////////////////////////////////////////////////////////////////////
  1034.             // initialize a permute vector that, given input vectors:
  1035.             //
  1036.             //    X = x0 x1 x2 x3
  1037.             //    Y = y0 y1 y2 y3
  1038.             //
  1039.             // will generate
  1040.             //    Z = y0 x0 y1 x1
  1041.             ////////////////////////////////////////////////////////////////////////////////
  1042.             vSinPerm = (vector unsigned char)(16, 17, 18, 19, 0, 1, 2, 3, 20, 21, 22, 23, 4, 5, 6, 7);        
  1043.         }
  1044.  
  1045.         ////////////////////////////////////////////////////////////////////////////////
  1046.         // initialize a permute vector that, given input vectors:
  1047.         //
  1048.         //    X = x0 x1 x2 x3
  1049.         //    Y = y0 y1 y2 y3
  1050.         //
  1051.         // will generate
  1052.         //    Z = x0 x1 y0 y1
  1053.         ////////////////////////////////////////////////////////////////////////////////
  1054.         vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  1055.  
  1056.         ////////////////////////////////////////////////////////////////////////////////
  1057.         // initialize a permute vector that, given input vectors:
  1058.         //
  1059.         //    X = x0 x1 x2 x3
  1060.         //    Y = y0 y1 y2 y3
  1061.         //
  1062.         // will generate
  1063.         //    Z = x2 x3 y2 y3
  1064.         ////////////////////////////////////////////////////////////////////////////////
  1065.         vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  1066.         
  1067.         vZero = (vector float)(0);
  1068.  
  1069.         
  1070.         ////////////////////////////////////////////////////////////////////////////////
  1071.         // start source pointers at start and end of high and low halves of the data
  1072.         ////////////////////////////////////////////////////////////////////////////////
  1073.         pInLoBottom = (vector float*)pData;
  1074.         pInHiBottom = pInLoBottom + len/4;
  1075.         pInLoTop = pInHiBottom - 1;
  1076.         pInHiTop = pInLoBottom + (len/2) - 1;
  1077.  
  1078.         ////////////////////////////////////////////////////////////////////////////////
  1079.         // start dest pointers at start and end of high and low halves of the data
  1080.         ////////////////////////////////////////////////////////////////////////////////
  1081.         pOutHiBottom = pInHiBottom;
  1082.         pOutHiTop = pInHiTop;
  1083.  
  1084.         pOutLoBottom = pInLoBottom;
  1085.         pOutLoTop = (pOutLoBottom + len/4) - 1;
  1086.  
  1087.         ////////////////////////////////////////////////////////////////////////////////
  1088.         //
  1089.         //    Given c = cos(w) and s = sin(w), if we
  1090.         //    want to find the cos and sin of w plus
  1091.         //    some small angle d, then we can do so
  1092.         //    by defining:
  1093.         //    
  1094.         //    a = 2 * ((sin(d/2)) ^ 2)
  1095.         //    b = sin(d)
  1096.         //    
  1097.         //    Then, we can calculate the cos and sin
  1098.         //    of the updated angle w+d as:
  1099.         //    
  1100.         //    cos(w+d) = c - ac - bs
  1101.         //    sin(w+d) = s - as + bc
  1102.         //    
  1103.         //    We will need to incrementally calculate
  1104.         //    cos(w) and sin(w), so we define the
  1105.         //    following scalar values.  We use scalar
  1106.         //    because we need the precision of doubles,
  1107.         //    and vectors are floats.    
  1108.         //
  1109.         ////////////////////////////////////////////////////////////////////////////////
  1110.  
  1111.         updateA = sin(2*PI/len);
  1112.         updateA *= updateA*2;
  1113.  
  1114.         updateB = sin(4*PI/len);
  1115.  
  1116.         ////////////////////////////////////////////////////////////////////////////////
  1117.         //
  1118.         // We want to have four cos and sin vectors
  1119.         // that are updated incrementally, using
  1120.         // the doubles that we have used to calculate
  1121.         // our new values.  To do this we have a
  1122.         // "transition" vector that allows us to get
  1123.         // our scalar values into the vector domain.
  1124.         //
  1125.         // Scalar values are stored into the elements
  1126.         // of the transition vector, and then 
  1127.         // our end cos and sin vectors are created
  1128.         // by permuting values out of our transition
  1129.         // vector and other previously created sin
  1130.         // and cos vectors.
  1131.         // 
  1132.         ////////////////////////////////////////////////////////////////////////////////
  1133.  
  1134.  
  1135.         ////////////////////////////////////////////////////////////////////////////////
  1136.         // set up vSinLo as
  1137.         // vSinLo = -sin(0) sin(0) -sin(pi/len) sin(pi/len)
  1138.         ////////////////////////////////////////////////////////////////////////////////
  1139.         ((float*)&vFTransition)[0] = 0;
  1140.         ((float*)&vFTransition)[1] = 0;
  1141.  
  1142.         newSin1 = sin(2*PI/len);
  1143.             
  1144.         ((float*)&vFTransition)[2] = newSin1*startSinMul;
  1145.         ((float*)&vFTransition)[3] = -newSin1*startSinMul;
  1146.  
  1147.         vSinLo = vFTransition;
  1148.  
  1149.         ////////////////////////////////////////////////////////////////////////////////
  1150.         // set up vSinHi as
  1151.         // vSinHi = -sin((len-2)*pi/len) sin((len-2)*pi/len) -sin((len-1)*pi/len) sin((len-1)*pi/len)
  1152.         ////////////////////////////////////////////////////////////////////////////////
  1153.         newSin2 = sin(4*PI/len);
  1154.         
  1155.         ((float*)&vFTransition)[0] = newSin2*startSinMul;    
  1156.         ((float*)&vFTransition)[1] = -newSin2*startSinMul;
  1157.         
  1158.         vSinHi = vFTransition;
  1159.  
  1160.         ///////////////////////////////////////////// 
  1161.         // set up vCosLo as
  1162.         // vCosLo = -cos(0) cos(0) -cos(pi/len) cos(pi/len)
  1163.         ////////////////////////////////////////////////////////////////////////////////
  1164.         ((float*)&vFTransition)[0] = 1;
  1165.         ((float*)&vFTransition)[1] = 1;
  1166.  
  1167.         newCos1 = cos(2*PI/len);
  1168.             
  1169.         ((float*)&vFTransition)[2] = newCos1;
  1170.         ((float*)&vFTransition)[3] = newCos1;
  1171.  
  1172.         vCosLo = vFTransition;
  1173.  
  1174.         ////////////////////////////////////////////////////////////////////////////////
  1175.         // set up vCosHi as
  1176.         // vCosHi = -cos((len-2)*pi/len) cos((len-2)*pi/len) -cos((len-1)*pi/len) cos((len-1)*pi/len)
  1177.         ////////////////////////////////////////////////////////////////////////////////
  1178.         newCos2 = cos(4*PI/len);
  1179.         
  1180.         ((float*)&vFTransition)[0] = newCos2;    
  1181.         ((float*)&vFTransition)[1] = newCos2;
  1182.         
  1183.         vCosHi = vec_sub(vZero, vFTransition);    
  1184.  
  1185.         if (isign == -1) {
  1186.             
  1187.             ////////////////////////////////////////////////////////////////////////////////
  1188.             // we are doing a forward FFT
  1189.             ////////////////////////////////////////////////////////////////////////////////
  1190.         
  1191.             for (i=0; i<len/16; i++) {
  1192.  
  1193.                 ////////////////////////////////////////////////////////////////////////////////
  1194.                 // calculate new sin, cos for next time through loop, using our incremental
  1195.                 // updating algorithm
  1196.                 ////////////////////////////////////////////////////////////////////////////////
  1197.  
  1198.                 tempCos1     = newCos1 - (updateA*newCos1  + updateB * newSin1);
  1199.                 newSin1     = newSin1 - (updateA*newSin1  - updateB * newCos1);
  1200.                 newCos1     = tempCos1;
  1201.  
  1202.                 tempCos2     = newCos2 - (updateA*newCos2  + updateB * newSin2);
  1203.                 newSin2     = newSin2 - (updateA*newSin2  - updateB * newCos2);
  1204.                 newCos2     = tempCos2;
  1205.  
  1206.                 ////////////////////////////////////////////////////////////////////////////////
  1207.                 // load input vectors
  1208.                 ////////////////////////////////////////////////////////////////////////////////
  1209.  
  1210.                 vLoBottom     = *pInLoBottom++;
  1211.                 vHiBottom     = *pInHiBottom++;
  1212.                 vLoTop         = *pInLoTop--;
  1213.                 vHiTop         = *pInHiTop--;
  1214.  
  1215.                 ////////////////////////////////////////////////////////////////////////////////
  1216.                 // store new cos & sin to transition vector
  1217.                 ////////////////////////////////////////////////////////////////////////////////
  1218.  
  1219.                 ((float*)&vFTransition)[0] = newSin2;
  1220.                 ((float*)&vFTransition)[1] = newSin1;
  1221.                 ((float*)&vFTransition)[2] = newCos2;
  1222.                 ((float*)&vFTransition)[3] = newCos1;
  1223.  
  1224.                 vFNegTransition    = vec_sub(vZero, vFTransition);
  1225.  
  1226.  
  1227.                 ////////////////////////////////////////////////////////////////////////////////
  1228.                 // calc sum of input data
  1229.                 ////////////////////////////////////////////////////////////////////////////////
  1230.  
  1231.                 *pOutLoBottom++     = vec_add(vLoBottom, vHiBottom);        
  1232.                 *pOutLoTop--         = vec_add(vLoTop, vHiTop);        
  1233.  
  1234.                 ////////////////////////////////////////////////////////////////////////////////
  1235.                 // calc difference of input data
  1236.                 ////////////////////////////////////////////////////////////////////////////////
  1237.                 
  1238.                 vDiffBottom     = vec_sub(vLoBottom, vHiBottom);
  1239.                 vDiffTop         = vec_sub(vLoTop, vHiTop);
  1240.  
  1241.                 ////////////////////////////////////////////////////////////////////////////////
  1242.                 // multiply difference by twist factor
  1243.                 ////////////////////////////////////////////////////////////////////////////////
  1244.                 
  1245.                 vTwistBottom    = vec_madd(vCosLo, vDiffBottom, vZero);        
  1246.                 vTwistTop        = vec_madd(vCosHi, vDiffTop, vZero);        
  1247.  
  1248.                 vSwappedDiffTop     = vec_perm(vDiffTop, vDiffTop, vSwapPairPerm);    
  1249.                 vSwappedDiffBottom    = vec_perm(vDiffBottom, vDiffBottom, vSwapPairPerm);    
  1250.                 
  1251.                 vTwistBottom    = vec_madd(vSinLo, vSwappedDiffBottom, vTwistBottom);
  1252.                 vTwistTop        = vec_madd(vSinHi, vSwappedDiffTop, vTwistTop);
  1253.  
  1254.                 ////////////////////////////////////////////////////////////////////////////////
  1255.                 // generate new cos & sin vectors from transition vector and previously
  1256.                 // calculated steps.
  1257.                 ////////////////////////////////////////////////////////////////////////////////
  1258.  
  1259.                 vCosLo = vec_sub(vZero, vec_perm(vCosHi, vFNegTransition, vCosLoPerm));
  1260.                 vCosHi = vec_mergel(vFNegTransition, vFNegTransition);
  1261.                 vSinLo = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1262.                 vSinLo = vec_sel(vSinHi, vSinLo, vHiPairSelect);
  1263.                 vSinHi = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1264.                 
  1265.  
  1266.                 ////////////////////////////////////////////////////////////////////////////////
  1267.                 // load input vectors for next sum & difference calculation
  1268.                 ////////////////////////////////////////////////////////////////////////////////
  1269.  
  1270.                 vLoBottom     = *pInLoBottom++;
  1271.                 vHiBottom     = *pInHiBottom++;
  1272.                 vLoTop         = *pInLoTop--;
  1273.                 vHiTop         = *pInHiTop--;
  1274.  
  1275.                 ////////////////////////////////////////////////////////////////////////////////
  1276.                 // store twist-multiplied difference.
  1277.                 ////////////////////////////////////////////////////////////////////////////////
  1278.                 
  1279.                 *pOutHiBottom++     = vTwistBottom;
  1280.                 *pOutHiTop--         = vTwistTop;
  1281.  
  1282.                 ////////////////////////////////////////////////////////////////////////////////
  1283.                 // calculate new sin, cos for next time through loop, using our incremental
  1284.                 // updating algorithm
  1285.                 ////////////////////////////////////////////////////////////////////////////////
  1286.  
  1287.                 tempCos1     = newCos1 - (updateA*newCos1  + updateB * newSin1);
  1288.                 newSin1     = newSin1 - (updateA*newSin1  - updateB * newCos1);
  1289.                 newCos1     = tempCos1;
  1290.  
  1291.                 tempCos2     = newCos2 - (updateA*newCos2  + updateB * newSin2);
  1292.                 newSin2     = newSin2 - (updateA*newSin2  - updateB * newCos2);
  1293.                 newCos2     = tempCos2;
  1294.  
  1295.  
  1296.                 ////////////////////////////////////////////////////////////////////////////////
  1297.                 // store new cos & sin to transition vector
  1298.                 ////////////////////////////////////////////////////////////////////////////////
  1299.  
  1300.                 ((float*)&vFTransition)[0] = newSin2;
  1301.                 ((float*)&vFTransition)[1] = newSin1;
  1302.                 ((float*)&vFTransition)[2] = newCos2;
  1303.                 ((float*)&vFTransition)[3] = newCos1;
  1304.  
  1305.                 vFNegTransition    = vec_sub(vZero, vFTransition);
  1306.  
  1307.  
  1308.                 ////////////////////////////////////////////////////////////////////////////////
  1309.                 // calc sum of input data
  1310.                 ////////////////////////////////////////////////////////////////////////////////
  1311.  
  1312.                 *pOutLoBottom++     = vec_add(vLoBottom, vHiBottom);        
  1313.                 *pOutLoTop--         = vec_add(vLoTop, vHiTop);        
  1314.  
  1315.                 ////////////////////////////////////////////////////////////////////////////////
  1316.                 // calc difference of input data
  1317.                 ////////////////////////////////////////////////////////////////////////////////
  1318.                 
  1319.                 vDiffBottom     = vec_sub(vLoBottom, vHiBottom);
  1320.                 vDiffTop         = vec_sub(vLoTop, vHiTop);
  1321.  
  1322.                 ////////////////////////////////////////////////////////////////////////////////
  1323.                 // multiply difference by twist factor
  1324.                 ////////////////////////////////////////////////////////////////////////////////
  1325.                 
  1326.                 vTwistBottom    = vec_madd(vCosLo, vDiffBottom, vZero);        
  1327.                 vTwistTop        = vec_madd(vCosHi, vDiffTop, vZero);        
  1328.  
  1329.                 vSwappedDiffTop     = vec_perm(vDiffTop, vDiffTop, vSwapPairPerm);    
  1330.                 vSwappedDiffBottom    = vec_perm(vDiffBottom, vDiffBottom, vSwapPairPerm);    
  1331.                 
  1332.                 vTwistBottom    = vec_madd(vSinLo, vSwappedDiffBottom, vTwistBottom);
  1333.                 vTwistTop        = vec_madd(vSinHi, vSwappedDiffTop, vTwistTop);
  1334.  
  1335.                 ////////////////////////////////////////////////////////////////////////////////
  1336.                 // generate new cos & sin vectors from transition vector and previously
  1337.                 // calculated steps.
  1338.                 ////////////////////////////////////////////////////////////////////////////////
  1339.  
  1340.                 vCosLo = vec_sub(vZero, vec_perm(vCosHi, vFNegTransition, vCosLoPerm));
  1341.                 vCosHi = vec_mergel(vFNegTransition, vFNegTransition);
  1342.                 vSinLo = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1343.                 vSinLo = vec_sel(vSinHi, vSinLo, vHiPairSelect);
  1344.                 vSinHi = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1345.                 
  1346.                 ////////////////////////////////////////////////////////////////////////////////
  1347.                 // store twist-multiplied difference.
  1348.                 ////////////////////////////////////////////////////////////////////////////////
  1349.                 
  1350.                 *pOutHiBottom++     = vTwistBottom;
  1351.                 *pOutHiTop--         = vTwistTop;
  1352.             
  1353.             }    
  1354.         } else {
  1355.  
  1356.             ////////////////////////////////////////////////////////////////////////////////
  1357.             // We are doing an inverse FFT, so we must adjust output by dividing by 2.
  1358.             ////////////////////////////////////////////////////////////////////////////////
  1359.  
  1360.             vOneHalf        = (vector float)(.5);
  1361.  
  1362.             for (i=0; i<len/16; i++) {
  1363.  
  1364.                 ////////////////////////////////////////////////////////////////////////////////
  1365.                 // calculate new sin, cos for next time through loop, using our incremental
  1366.                 // updating algorithm
  1367.                 ////////////////////////////////////////////////////////////////////////////////
  1368.  
  1369.                 tempCos1     = newCos1 - (updateA*newCos1  + updateB * newSin1);
  1370.                 newSin1     = newSin1 - (updateA*newSin1  - updateB * newCos1);
  1371.                 newCos1     = tempCos1;
  1372.  
  1373.                 tempCos2     = newCos2 - (updateA*newCos2  + updateB * newSin2);
  1374.                 newSin2     = newSin2 - (updateA*newSin2  - updateB * newCos2);
  1375.                 newCos2     = tempCos2;
  1376.  
  1377.                 ////////////////////////////////////////////////////////////////////////////////
  1378.                 // load input vectors
  1379.                 ////////////////////////////////////////////////////////////////////////////////
  1380.  
  1381.                 vLoBottom     = *pInLoBottom++;
  1382.                 vHiBottom     = *pInHiBottom++;
  1383.                 vLoTop         = *pInLoTop--;
  1384.                 vHiTop         = *pInHiTop--;
  1385.  
  1386.                 ////////////////////////////////////////////////////////////////////////////////
  1387.                 // do inverse adjusting by dividing all elements by two. 
  1388.                 ////////////////////////////////////////////////////////////////////////////////
  1389.  
  1390.                 vLoBottom = vec_madd(vLoBottom, vOneHalf, vZero);
  1391.                 vHiBottom = vec_madd(vHiBottom, vOneHalf, vZero);
  1392.                 vLoTop = vec_madd(vLoTop, vOneHalf, vZero);
  1393.                 vHiTop = vec_madd(vHiTop, vOneHalf, vZero);
  1394.  
  1395.                 ////////////////////////////////////////////////////////////////////////////////
  1396.                 // store new cos & sin to transition vector
  1397.                 ////////////////////////////////////////////////////////////////////////////////
  1398.  
  1399.                 ((float*)&vFTransition)[0] = newSin2;
  1400.                 ((float*)&vFTransition)[1] = newSin1;
  1401.                 ((float*)&vFTransition)[2] = newCos2;
  1402.                 ((float*)&vFTransition)[3] = newCos1;
  1403.  
  1404.                 vFNegTransition    = vec_sub(vZero, vFTransition);
  1405.  
  1406.  
  1407.                 ////////////////////////////////////////////////////////////////////////////////
  1408.                 // calc sum of input data
  1409.                 ////////////////////////////////////////////////////////////////////////////////
  1410.  
  1411.                 *pOutLoBottom++     = vec_add(vLoBottom, vHiBottom);        
  1412.                 *pOutLoTop--         = vec_add(vLoTop, vHiTop);        
  1413.  
  1414.                 ////////////////////////////////////////////////////////////////////////////////
  1415.                 // calc difference of input data
  1416.                 ////////////////////////////////////////////////////////////////////////////////
  1417.                 
  1418.                 vDiffBottom     = vec_sub(vLoBottom, vHiBottom);
  1419.                 vDiffTop         = vec_sub(vLoTop, vHiTop);
  1420.  
  1421.                 ////////////////////////////////////////////////////////////////////////////////
  1422.                 // multiply difference by twist factor
  1423.                 ////////////////////////////////////////////////////////////////////////////////
  1424.                 
  1425.                 vTwistBottom    = vec_madd(vCosLo, vDiffBottom, vZero);        
  1426.                 vTwistTop        = vec_madd(vCosHi, vDiffTop, vZero);        
  1427.  
  1428.                 vSwappedDiffTop     = vec_perm(vDiffTop, vDiffTop, vSwapPairPerm);    
  1429.                 vSwappedDiffBottom    = vec_perm(vDiffBottom, vDiffBottom, vSwapPairPerm);    
  1430.                 
  1431.                 vTwistBottom    = vec_madd(vSinLo, vSwappedDiffBottom, vTwistBottom);
  1432.                 vTwistTop        = vec_madd(vSinHi, vSwappedDiffTop, vTwistTop);
  1433.  
  1434.                 ////////////////////////////////////////////////////////////////////////////////
  1435.                 // generate new cos & sin vectors from transition vector and previously
  1436.                 // calculated steps.
  1437.                 ////////////////////////////////////////////////////////////////////////////////
  1438.  
  1439.                 vCosLo = vec_sub(vZero, vec_perm(vCosHi, vFNegTransition, vCosLoPerm));
  1440.                 vCosHi = vec_mergel(vFNegTransition, vFNegTransition);
  1441.                 vSinLo = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1442.                 vSinLo = vec_sel(vSinHi, vSinLo, vHiPairSelect);
  1443.                 vSinHi = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1444.                                 
  1445.                 ////////////////////////////////////////////////////////////////////////////////
  1446.                 // store twist-multiplied difference.
  1447.                 ////////////////////////////////////////////////////////////////////////////////
  1448.                 
  1449.                 *pOutHiBottom++     = vTwistBottom;
  1450.                 *pOutHiTop--         = vTwistTop;
  1451.  
  1452.                 ////////////////////////////////////////////////////////////////////////////////
  1453.                 // calculate new sin, cos for next time through loop, using our incremental
  1454.                 // updating algorithm
  1455.                 ////////////////////////////////////////////////////////////////////////////////
  1456.  
  1457.                 tempCos1     = newCos1 - (updateA*newCos1  + updateB * newSin1);
  1458.                 newSin1     = newSin1 - (updateA*newSin1  - updateB * newCos1);
  1459.                 newCos1     = tempCos1;
  1460.  
  1461.                 tempCos2     = newCos2 - (updateA*newCos2  + updateB * newSin2);
  1462.                 newSin2     = newSin2 - (updateA*newSin2  - updateB * newCos2);
  1463.                 newCos2     = tempCos2;
  1464.  
  1465.  
  1466.                 ////////////////////////////////////////////////////////////////////////////////
  1467.                 // load input vectors
  1468.                 ////////////////////////////////////////////////////////////////////////////////
  1469.  
  1470.                 vLoBottom     = *pInLoBottom++;
  1471.                 vHiBottom     = *pInHiBottom++;
  1472.                 vLoTop         = *pInLoTop--;
  1473.                 vHiTop         = *pInHiTop--;
  1474.  
  1475.                 ////////////////////////////////////////////////////////////////////////////////
  1476.                 // do inverse adjusting by dividing all elements by two. 
  1477.                 ////////////////////////////////////////////////////////////////////////////////
  1478.  
  1479.                 vLoBottom = vec_madd(vLoBottom, vOneHalf, vZero);
  1480.                 vHiBottom = vec_madd(vHiBottom, vOneHalf, vZero);
  1481.                 vLoTop = vec_madd(vLoTop, vOneHalf, vZero);
  1482.                 vHiTop = vec_madd(vHiTop, vOneHalf, vZero);
  1483.  
  1484.                 ////////////////////////////////////////////////////////////////////////////////
  1485.                 // store new cos & sin to transition vector
  1486.                 ////////////////////////////////////////////////////////////////////////////////
  1487.  
  1488.                 ((float*)&vFTransition)[0] = newSin2;
  1489.                 ((float*)&vFTransition)[1] = newSin1;
  1490.                 ((float*)&vFTransition)[2] = newCos2;
  1491.                 ((float*)&vFTransition)[3] = newCos1;
  1492.  
  1493.                 vFNegTransition    = vec_sub(vZero, vFTransition);
  1494.  
  1495.                 ////////////////////////////////////////////////////////////////////////////////
  1496.                 // calc sum of input data
  1497.                 ////////////////////////////////////////////////////////////////////////////////
  1498.  
  1499.                 *pOutLoBottom++     = vec_add(vLoBottom, vHiBottom);        
  1500.                 *pOutLoTop--         = vec_add(vLoTop, vHiTop);        
  1501.  
  1502.                 ////////////////////////////////////////////////////////////////////////////////
  1503.                 // calc difference of input data
  1504.                 ////////////////////////////////////////////////////////////////////////////////
  1505.                 
  1506.                 vDiffBottom     = vec_sub(vLoBottom, vHiBottom);
  1507.                 vDiffTop         = vec_sub(vLoTop, vHiTop);
  1508.  
  1509.                 ////////////////////////////////////////////////////////////////////////////////
  1510.                 // multiply difference by twist factor
  1511.                 ////////////////////////////////////////////////////////////////////////////////
  1512.                 
  1513.                 vTwistBottom    = vec_madd(vCosLo, vDiffBottom, vZero);        
  1514.                 vTwistTop        = vec_madd(vCosHi, vDiffTop, vZero);        
  1515.  
  1516.                 vSwappedDiffTop     = vec_perm(vDiffTop, vDiffTop, vSwapPairPerm);    
  1517.                 vSwappedDiffBottom    = vec_perm(vDiffBottom, vDiffBottom, vSwapPairPerm);    
  1518.                 
  1519.                 vTwistBottom    = vec_madd(vSinLo, vSwappedDiffBottom, vTwistBottom);
  1520.                 vTwistTop        = vec_madd(vSinHi, vSwappedDiffTop, vTwistTop);
  1521.  
  1522.                 ////////////////////////////////////////////////////////////////////////////////
  1523.                 // generate new cos & sin vectors from transition vector and previously
  1524.                 // calculated steps.
  1525.                 ////////////////////////////////////////////////////////////////////////////////
  1526.  
  1527.                 vCosLo = vec_sub(vZero, vec_perm(vCosHi, vFNegTransition, vCosLoPerm));
  1528.                 vCosHi = vec_mergel(vFNegTransition, vFNegTransition);
  1529.                 vSinLo = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1530.                 vSinLo = vec_sel(vSinHi, vSinLo, vHiPairSelect);
  1531.                 vSinHi = vec_perm(vFTransition, vFNegTransition, vSinPerm);
  1532.                 
  1533.                 ////////////////////////////////////////////////////////////////////////////////
  1534.                 // store twist-multiplied difference.
  1535.                 ////////////////////////////////////////////////////////////////////////////////
  1536.                 
  1537.                 *pOutHiBottom++     = vTwistBottom;
  1538.                 *pOutHiTop--         = vTwistTop;
  1539.             
  1540.             }    
  1541.         }
  1542.  
  1543.         ////////////////////////////////////////////////////////////////////////////////
  1544.         // perform N/2-length FFT on high half of data
  1545.         ////////////////////////////////////////////////////////////////////////////////
  1546.         result = FFTComplex(pData+len, len/2, isign);
  1547.         
  1548.         if (result == noErr) {
  1549.         
  1550.             ////////////////////////////////////////////////////////////////////////////////
  1551.             // perform N/2-length FFT on low half of data
  1552.             ////////////////////////////////////////////////////////////////////////////////
  1553.             result = FFTComplex(pData, len/2, isign);
  1554.             
  1555.             if (result == noErr) {
  1556.         
  1557.  
  1558.                 ////////////////////////////////////////////////////////////////////////////////
  1559.                 // Move low half of data to temporary buffer, which will leave room in
  1560.                 // main data space to merge elements of low and high data in to the original
  1561.                 // buffer space.
  1562.                 ////////////////////////////////////////////////////////////////////////////////
  1563.                 {                                
  1564.                     vector float *pSource = (vector float*)pData;
  1565.                     vector float *pDest = *(vector float**)gTempBufferHandle;
  1566.                     
  1567.                     vector float v1, v2, v3, v4;
  1568.                     
  1569.                     for (i = 0; i < len/16; i++) {
  1570.                         v1 = *pSource++;
  1571.                         v2 = *pSource++;
  1572.                         v3 = *pSource++;
  1573.                         v4 = *pSource++;
  1574.                         
  1575.                         
  1576.                         *pDest++ = v1;
  1577.                         *pDest++ = v2;
  1578.                         *pDest++ = v3;
  1579.                         *pDest++ = v4;
  1580.                     }
  1581.                     
  1582.                 }
  1583.  
  1584.                 ////////////////////////////////////////////////////////////////////////////////
  1585.                 // Merge low and high halves of data back into original data buffer.  Elements
  1586.                 // are merged so that, given high and low signals X1 and X2, resulting merged
  1587.                 // signal is X1(0), X2(0), X1(1), X2(1), ... , X1(N/2-1), X2(N/2-1)
  1588.                 ////////////////////////////////////////////////////////////////////////////////
  1589.                 pInHiBottom = (vector float*)*gTempBufferHandle;
  1590.                 pInHiTop = (vector float*)(pData+len);
  1591.                 pOutLoBottom = (vector float*)pData;    
  1592.  
  1593.                 for (i=0; i<len/8; i++) {
  1594.                     vector float    vInEven1, vInOdd1;
  1595.                     vector float    vInEven2, vInOdd2;
  1596.                     vector float    vOut1, vOut2, vOut3, vOut4;
  1597.                             
  1598.                     vInEven1 = *pInHiBottom++;
  1599.                     vInOdd1 = *pInHiTop++;
  1600.                     vInEven2 = *pInHiBottom++;
  1601.                     vInOdd2 = *pInHiTop++;
  1602.                     
  1603.                     vOut1 = vec_perm(vInEven1, vInOdd1, vMergeHiPairPerm);
  1604.                     vOut2 = vec_perm(vInEven1, vInOdd1, vMergeLoPairPerm);
  1605.                     vOut3 = vec_perm(vInEven2, vInOdd2, vMergeHiPairPerm);
  1606.                     vOut4 = vec_perm(vInEven2, vInOdd2, vMergeLoPairPerm);
  1607.                     
  1608.                     *pOutLoBottom++ = vOut1;
  1609.                     *pOutLoBottom++ = vOut2;
  1610.                     *pOutLoBottom++ = vOut3;
  1611.                     *pOutLoBottom++ = vOut4;
  1612.                 }
  1613.             }
  1614.             
  1615.         }
  1616.     }
  1617.         
  1618.     return result;
  1619. }
  1620.  
  1621.  
  1622.  
  1623. ////////////////////////////////////////////////////////////////////////////////
  1624. //    fft_matrix_forward_columnwise
  1625. //
  1626. //    Performs a recursive 2D matrix FFT on the data pointed to by
  1627. // pData. It leaves data in columnwise order.
  1628. //
  1629. //    There are three steps to the 2D matrix FFT.  First, a FFT is performed on
  1630. // each column of the matrix.  Second, each element in the matrix is multiplied
  1631. // by a twist factor.  In a length N signal, element X(j, k) is multiplied by
  1632. // e^(+/- 2 pi i j k / N ). Finally, an FFT is performed on each row of the
  1633. // matrix.  The resulting data is the FFT of the original signal, stored in
  1634. // columnwise order.
  1635. //    
  1636. //
  1637. ////////////////////////////////////////////////////////////////////////////////
  1638. static OSErr    fft_matrix_forward_columnwise(float *pData, long length)
  1639. {
  1640.     long        i, j;
  1641.     long        pow;
  1642.     float        *pRow;
  1643.     long        rowCount;
  1644.     long        colCount;
  1645.     long        rowPower;
  1646.     long        colPower;
  1647.     Handle        rowBufferHandle = nil;
  1648.     OSErr        result = noErr;
  1649.             
  1650.     pow = log2max(length);
  1651.     
  1652.     ////////////////////////////////////////////////////////////////////////////////
  1653.     // length must be an exact power of 2
  1654.     ////////////////////////////////////////////////////////////////////////////////
  1655.     if ((1 << pow) != length) {
  1656.         return paramErr;
  1657.     }
  1658.     
  1659.     ////////////////////////////////////////////////////////////////////////////////
  1660.     // data must be 16-byte aligned because of vector load/store requirements
  1661.     ////////////////////////////////////////////////////////////////////////////////
  1662.     if (((long)pData) & 0x0F) {
  1663.         return paramErr;
  1664.     }
  1665.     
  1666.     ////////////////////////////////////////////////////////////////////////////////
  1667.     // calculate dimensions of matrix.  If matrix can not be square, then the
  1668.     // column count will be 2X the row count    
  1669.     ////////////////////////////////////////////////////////////////////////////////
  1670.  
  1671.     rowPower = pow / 2;
  1672.     
  1673.     colPower = rowPower;
  1674.     
  1675.     if (pow & 1) colPower++;
  1676.  
  1677.     rowCount = 1<<rowPower;
  1678.     colCount = 1<<colPower;
  1679.  
  1680.     ////////////////////////////////////////////////////////////////////////////////
  1681.     // allocate a buffer that will be used for column ferrying, and can store
  1682.     // two columns at a time.
  1683.     ////////////////////////////////////////////////////////////////////////////////
  1684.  
  1685.     rowBufferHandle = NewHandle(2*2*sizeof(float)*rowCount);
  1686.     
  1687.     result = MemError();
  1688.     
  1689.     if (result == noErr) {
  1690.         vector float            *pCurrentColumn;
  1691.         vector float            vIn1, vIn2;
  1692.         vector float            vOut1, vOut2;
  1693.         vector unsigned char    vMergeHiPairPerm;
  1694.         vector unsigned char    vMergeLoPairPerm;
  1695.         vector float            *pSplit1, *pSplit2;
  1696.         float                    *pFFT1, *pFFT2;
  1697.         vector unsigned char    vSwappedPerm;
  1698.         vector float            vSinSignMultiplier;
  1699.         vector float            vCosTwistA0;
  1700.         vector float            vCosTwistA1;
  1701.  
  1702.         vector float            vCosTemp0;
  1703.         vector float            vCosTemp1;
  1704.  
  1705.         vector float            vSinTwistA0;
  1706.         vector float            vSinTwistA1;
  1707.  
  1708.         vector float            vA;
  1709.         vector float            vB;
  1710.  
  1711.         vector float            vTransition;
  1712.         vector float            vZero = (vector float)(0);
  1713.         
  1714.         
  1715.         double                    fTemp;
  1716.         double                    baseAngle1;
  1717.         double                    baseAngle2;
  1718.  
  1719.         double                    fSinBaseAngle1;
  1720.         double                    fSinBaseAngle2;
  1721.         
  1722.         ////////////////////////////////////////////////////////////////////////////////
  1723.         // initialize a permute vector that, given input vectors:
  1724.         //
  1725.         //    X = x0 x1 x2 x3
  1726.         //    Y = y0 y1 y2 y3
  1727.         //
  1728.         // will generate
  1729.         //    Z = x0 x1 y0 y1
  1730.         ////////////////////////////////////////////////////////////////////////////////
  1731.         vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  1732.  
  1733.         ////////////////////////////////////////////////////////////////////////////////
  1734.         // initialize a permute vector that, given input vectors:
  1735.         //
  1736.         //    X = x0 x1 x2 x3
  1737.         //    Y = y0 y1 y2 y3
  1738.         //
  1739.         // will generate
  1740.         //    Z = x2 x3 y2 y3
  1741.         ////////////////////////////////////////////////////////////////////////////////
  1742.         vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  1743.         
  1744.         ////////////////////////////////////////////////////////////////////////////////
  1745.         // initialize a permute vector that, given input vectors:
  1746.         //
  1747.         //    X = x0 x1 x2 x3
  1748.         //    Y = y0 y1 y2 y3
  1749.         //
  1750.         // will generate
  1751.         //    Z = x1 x0 x3 y2
  1752.         ////////////////////////////////////////////////////////////////////////////////
  1753.         vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  1754.         
  1755.         ////////////////////////////////////////////////////////////////////////////////
  1756.         // vSinSignMultiplier is a vector used to create a vector in the form
  1757.         // sin(x) -sin(x) sin(y) -sin(y)
  1758.         ////////////////////////////////////////////////////////////////////////////////
  1759.  
  1760.         vSinSignMultiplier = (vector float)(1, -1, 1, -1);    
  1761.         
  1762.         ////////////////////////////////////////////////////////////////////////////////
  1763.         // we now loop through all columns, two columns at a time, and perform column
  1764.         // ferrying FFTs on the columns.  We first copy the columns to a separate
  1765.         // buffer, then perform the FFTs, and finally copy them back to their original
  1766.         // column positions
  1767.         ////////////////////////////////////////////////////////////////////////////////
  1768.  
  1769.         for (i=0; i<colCount/2; i++) {
  1770.         
  1771.             ////////////////////////////////////////////////////////////////////////////////
  1772.             // set up vectors for incremental updating of cos & sin vectors
  1773.             //
  1774.             // Given c = cos(w) and s = sin(w), if we want to find the cos and sin of w plus
  1775.             // some small angle d, then we can do so by defining:
  1776.             //    
  1777.             // a = 2 * ((sin(d/2)) ^ 2)
  1778.             // b = sin(d)
  1779.             // 
  1780.             // Then, we can calculate the cos and sin of the updated angle w+d as:
  1781.             // 
  1782.             // cos(w+d) = c - ac - bs
  1783.             // sin(w+d) = s - as + bc
  1784.             // 
  1785.             // the vectors vA and vB contain these increment factors a and b.  Note that
  1786.             // each outer loop iteration requires different increment angles.  Looking at
  1787.             // the matrix, the angle multipliers that we use for our cos & sin twist
  1788.             // multipliers look something like:
  1789.             //
  1790.             //        0/N        0/N        0/N        0/N        0/N        0/N        0/N    ...    0/N
  1791.             //        0/N        1/N        2/N        3/N        4/N        5/N        6/N        
  1792.             //        0/N        2/N        4/N        6/N        8/N        10/N    12/N    .
  1793.             //        0/N        3/N        6/N        9/N        12/N    15/N    18/N    .    
  1794.             //        0/N        4/N        8/N        12/N    16/N    20/N    24/N
  1795.             //        .        .
  1796.             //        .        .
  1797.             //        0/N                                            ...            (N-1)(N-1)
  1798.             //
  1799.             // Since we're doing two columns at a time, the vA and vB vectors
  1800.             // need to have two different sets of increment values.  For example, for
  1801.             // the third and fourth columns (handled in the second time through the
  1802.             // outer loop) each row increments by 2/N and 3/N.  Since we actually 
  1803.             // have two sets of twist multiplier vectors, we skip a row for each, so
  1804.             // the increment angle is doubled.  This helps reduce calculation dependencies
  1805.             // and cuts the number of increment iterations in half, which helps reduce
  1806.             // errors in the single-precision calculations used.
  1807.             //        
  1808.             ////////////////////////////////////////////////////////////////////////////////
  1809.  
  1810.             baseAngle1 = 4*i*PI/(colCount*rowCount);
  1811.             baseAngle2 = (2*(2*i+1)*PI)/(colCount*rowCount);
  1812.  
  1813.             fSinBaseAngle1 = sin(baseAngle1);
  1814.             fTemp = 2*fSinBaseAngle1*fSinBaseAngle1;
  1815.             
  1816.             ((float*)&vTransition)[0] = fTemp;
  1817.             ((float*)&vTransition)[2] = sin(2*baseAngle1);
  1818.  
  1819.             fSinBaseAngle2 = sin(baseAngle2);
  1820.             fTemp = 2*fSinBaseAngle2*fSinBaseAngle2;
  1821.  
  1822.             ((float*)&vTransition)[1] = fTemp;
  1823.             ((float*)&vTransition)[3] = sin(2*baseAngle2);
  1824.  
  1825.             vA = vec_mergeh(vTransition, vTransition);
  1826.             vB = vec_mergel(vTransition, vTransition);
  1827.             
  1828.             vB = vec_madd(vB, vSinSignMultiplier, vZero);
  1829.  
  1830.             ////////////////////////////////////////////////////////////////////////////////
  1831.             //    Set up the initial twist multiplier vectors for the beginning of this
  1832.             // column.  Values are calculated in the scalar domain, and then
  1833.             // transferred to the vector domain via the vTransition vector.
  1834.             ////////////////////////////////////////////////////////////////////////////////
  1835.             
  1836.             ((float*)&vTransition)[0] = 1;
  1837.             
  1838.             ((float*)&vTransition)[2] = cos(baseAngle1);
  1839.             ((float*)&vTransition)[3] = cos(baseAngle2);
  1840.             
  1841.             vCosTwistA0 = vec_splat(vTransition, 0);
  1842.             vCosTwistA1 = vec_mergel(vTransition, vTransition);
  1843.             
  1844.             vSinTwistA0 = vZero;
  1845.             
  1846.             ((float*)&vTransition)[2] = fSinBaseAngle1;
  1847.             ((float*)&vTransition)[3] = fSinBaseAngle2;
  1848.                                     
  1849.             vSinTwistA1 = vec_mergel(vTransition, vTransition);
  1850.             vSinTwistA1 = vec_madd(vSinTwistA1, vSinSignMultiplier, vZero);
  1851.  
  1852.             ////////////////////////////////////////////////////////////////////////////////
  1853.             // initialize pointers in temporary buffer for storing copied columns.
  1854.             ////////////////////////////////////////////////////////////////////////////////
  1855.         
  1856.             pSplit1 = *(vector float**)rowBufferHandle;
  1857.             pSplit2 = pSplit1 + rowCount / 2;
  1858.             
  1859.             ////////////////////////////////////////////////////////////////////////////////
  1860.             // point at top of columns to be copied
  1861.             ////////////////////////////////////////////////////////////////////////////////
  1862.  
  1863.             pCurrentColumn = ((vector float*)pData) + i;
  1864.         
  1865.             ////////////////////////////////////////////////////////////////////////////////
  1866.             // loop through all rows in the current column, copying elements to the
  1867.             // temporary buffer.  We load two rows at a time, and permute the vectors
  1868.             // to create a single vector that contains the appropriate column elements
  1869.             // from both rows.
  1870.             ////////////////////////////////////////////////////////////////////////////////
  1871.  
  1872.             for (j=0; j < rowCount/2; j++) {
  1873.  
  1874.                 ////////////////////////////////////////////////////////////////////////////////
  1875.                 // read in two rows worth of vectors (two rows X two columns)
  1876.                 ////////////////////////////////////////////////////////////////////////////////
  1877.  
  1878.                 vIn1 = *pCurrentColumn;
  1879.                 pCurrentColumn += colCount/2;
  1880.                 vIn2 = *pCurrentColumn;
  1881.                 pCurrentColumn += colCount/2;
  1882.                 
  1883.                 ////////////////////////////////////////////////////////////////////////////////
  1884.                 // permute the vectors so that the two left column entries are in one vector
  1885.                 // and the two right column entries are in one vector
  1886.                 ////////////////////////////////////////////////////////////////////////////////
  1887.  
  1888.                 vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  1889.                 vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  1890.                 
  1891.                 ////////////////////////////////////////////////////////////////////////////////
  1892.                 // store the split columns to the appropriate buffers
  1893.                 ////////////////////////////////////////////////////////////////////////////////
  1894.  
  1895.                 *pSplit1++ = vOut1;
  1896.                 *pSplit2++ = vOut2;
  1897.             }
  1898.  
  1899.             ////////////////////////////////////////////////////////////////////////////////
  1900.             // perform FFTs on the two columns of data that we have copied to the temp
  1901.             // buffer
  1902.             ////////////////////////////////////////////////////////////////////////////////
  1903.         
  1904.             pFFT1 = *(float **)rowBufferHandle;
  1905.             pFFT2 = pFFT1 + 2*rowCount;
  1906.             
  1907.             result = FFTComplex(pFFT1, rowCount, -1);
  1908.             if (result != noErr) break;
  1909.             
  1910.             result = FFTComplex(pFFT2, rowCount, -1);
  1911.             if (result != noErr) break;
  1912.                 
  1913.             ////////////////////////////////////////////////////////////////////////////////
  1914.             // point at the beginning of the two copied column buffers, and at the top
  1915.             // of the columns in the matrix where we will store them back.
  1916.             ////////////////////////////////////////////////////////////////////////////////
  1917.  
  1918.             pSplit1 = *(vector float**)rowBufferHandle;
  1919.             pSplit2 = pSplit1 + rowCount / 2;
  1920.             pCurrentColumn = ((vector float*)pData) + i;
  1921.  
  1922.             ////////////////////////////////////////////////////////////////////////////////
  1923.             // loop through all of the column entries that are stored in the temp buffer,
  1924.             // and merge them to be stored back into the columns of the matrix.  At the
  1925.             // same time, we perform the twist multiply on the entries.
  1926.             ////////////////////////////////////////////////////////////////////////////////
  1927.  
  1928.             for (j=0; j < rowCount/2; j++) {
  1929.                 vector float    vNew1, vNew2;
  1930.             
  1931.                 ////////////////////////////////////////////////////////////////////////////////
  1932.                 // get two vectors of column data
  1933.                 ////////////////////////////////////////////////////////////////////////////////
  1934.  
  1935.                 vIn1 = *pSplit1++;
  1936.                 vIn2 = *pSplit2++;
  1937.                 
  1938.                 ////////////////////////////////////////////////////////////////////////////////
  1939.                 // turn them into row vectors
  1940.                 ////////////////////////////////////////////////////////////////////////////////
  1941.                 
  1942.                 vNew1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  1943.                 vNew2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  1944.                 
  1945.                 ////////////////////////////////////////////////////////////////////////////////
  1946.                 // do twist multiplication on both row vectors
  1947.                 ////////////////////////////////////////////////////////////////////////////////
  1948.  
  1949.                 vOut1 = vec_madd(vCosTwistA0, vNew1, vZero);
  1950.                 vOut1 = vec_madd(vSinTwistA0, vec_perm(vNew1, vNew1, vSwappedPerm), vOut1);
  1951.  
  1952.                 vOut2 = vec_madd(vCosTwistA1, vNew2, vZero);
  1953.                 vOut2 = vec_madd(vSinTwistA1, vec_perm(vNew2, vNew2, vSwappedPerm), vOut2);
  1954.                 
  1955.                 ////////////////////////////////////////////////////////////////////////////////
  1956.                 // store row vectors back into the matrix
  1957.                 ////////////////////////////////////////////////////////////////////////////////
  1958.                 
  1959.                 *pCurrentColumn = vOut1;
  1960.                 pCurrentColumn += colCount / 2;
  1961.                 *pCurrentColumn = vOut2;                
  1962.                 pCurrentColumn += colCount / 2;
  1963.                                 
  1964.                 ////////////////////////////////////////////////////////////////////////////////
  1965.                 // update sin & cos vectors for twist multiply
  1966.                 ////////////////////////////////////////////////////////////////////////////////
  1967.  
  1968.                 vCosTemp0 = vec_nmsub(vCosTwistA0, vA, vCosTwistA0);
  1969.                 vCosTemp0 = vec_nmsub(vSinTwistA0, vB, vCosTemp0);
  1970.  
  1971.                 vSinTwistA0 = vec_nmsub(vSinTwistA0, vA, vSinTwistA0);
  1972.                 vSinTwistA0 = vec_madd (vCosTwistA0, vB, vSinTwistA0);
  1973.  
  1974.                 vCosTwistA0 = vCosTemp0;
  1975.  
  1976.                 vCosTemp1 = vec_nmsub(vCosTwistA1, vA, vCosTwistA1);
  1977.                 vCosTemp1 = vec_nmsub(vSinTwistA1, vB, vCosTemp1);
  1978.  
  1979.                 vSinTwistA1 = vec_nmsub(vSinTwistA1, vA, vSinTwistA1);
  1980.                 vSinTwistA1 = vec_madd (vCosTwistA1, vB, vSinTwistA1);
  1981.  
  1982.                 vCosTwistA1 = vCosTemp1;
  1983.             }
  1984.                         
  1985.         
  1986.         }
  1987.         
  1988.         if (result == noErr) {
  1989.             ////////////////////////////////////////////////////////////////////////////////
  1990.             // finally, loop through all rows of matrix, performing an FFT on each row
  1991.             ////////////////////////////////////////////////////////////////////////////////
  1992.  
  1993.             pRow = pData;
  1994.             
  1995.             for (i=rowCount-1; i>=0; i--) {
  1996.                 result = FFTComplex(pRow+i*(colCount*2), colCount, -1);
  1997.                 if (result != noErr) break;
  1998.             }
  1999.         }
  2000.         
  2001.     }
  2002.  
  2003.     if (rowBufferHandle) {
  2004.         DisposeHandle(rowBufferHandle);
  2005.     }
  2006.  
  2007.     return result;
  2008.  
  2009. }
  2010.  
  2011. ////////////////////////////////////////////////////////////////////////////////
  2012. //    fft_matrix_inverse_columnwise
  2013. //
  2014. //    Performs a recursive 2D matrix inverse FFT on the data pointed
  2015. // to by pData. It assumes that the data is in columnwise order, and returns the
  2016. // resulting data in "normal" linear (lexicographic) order.
  2017. //
  2018. //    There are three steps to the 2D matrix inverse FFT.  First, a FFT is
  2019. // performed on each row of the matrix.  Second, each element in the matrix is
  2020. // multiplied by a twist factor. In a length N signal, element X(j, k) is
  2021. // multiplied by e^(+/- 2 pi i j k / N ). Finally, an FFT is performed on each
  2022. // column of the matrix.  The resulting data is the recovered signal from the
  2023. // inverse FFT, in linear order.
  2024. //
  2025. ////////////////////////////////////////////////////////////////////////////////
  2026. static OSErr    fft_matrix_inverse_columnwise(float *pData, long length)
  2027. {
  2028.     long        i, j;
  2029.     long        pow;
  2030.     float        *pRow;
  2031.     long        rowCount;
  2032.     long        colCount;
  2033.     long        rowPower;
  2034.     long        colPower;
  2035.     Handle        rowBufferHandle = nil;
  2036.     OSErr        result = noErr;
  2037.             
  2038.     pow = log2max(length);
  2039.     
  2040.     ////////////////////////////////////////////////////////////////////////////////
  2041.     // length must be an exact power of 2
  2042.     ////////////////////////////////////////////////////////////////////////////////
  2043.     if ((1 << pow) != length) {
  2044.         return paramErr;
  2045.     }
  2046.     
  2047.     ////////////////////////////////////////////////////////////////////////////////
  2048.     // data must be 16-byte aligned because of vector load/store requirements
  2049.     ////////////////////////////////////////////////////////////////////////////////
  2050.     if (((long)pData) & 0x0F) {
  2051.         return paramErr;
  2052.     }
  2053.  
  2054.  
  2055.      ////////////////////////////////////////////////////////////////////////////////
  2056.     // calculate dimensions of matrix.  If matrix can not be square, then the
  2057.     // column count will be 2X the row count    
  2058.     ////////////////////////////////////////////////////////////////////////////////
  2059.  
  2060.     rowPower = pow / 2;
  2061.  
  2062.     colPower = rowPower;
  2063.  
  2064.     if (pow & 1) colPower++;
  2065.  
  2066.     rowCount = 1<<rowPower;
  2067.     colCount = 1<<colPower;
  2068.  
  2069.     ////////////////////////////////////////////////////////////////////////////////
  2070.     // allocate a buffer that will be used for column ferrying, and can store
  2071.     // two columns at a time.
  2072.     ////////////////////////////////////////////////////////////////////////////////
  2073.  
  2074.     rowBufferHandle = NewHandle(2*2*sizeof(float)*rowCount);
  2075.  
  2076.     result = MemError();
  2077.     
  2078.     if (result == noErr) {
  2079.         vector float            *pCurrentColumn;
  2080.         vector float            vIn1, vIn2;
  2081.         vector float            vOut1, vOut2;
  2082.         vector unsigned char    vMergeHiPairPerm;
  2083.         vector unsigned char    vMergeLoPairPerm;
  2084.         vector float            *pSplit1, *pSplit2;
  2085.         float                    *pFFT1, *pFFT2;
  2086.         vector unsigned char    vSwappedPerm;
  2087.         vector float            vSinSignMultiplier;
  2088.         vector float            vCosTwistA0;
  2089.         vector float            vCosTwistA1;
  2090.  
  2091.         vector float            vCosTemp0;
  2092.         vector float            vCosTemp1;
  2093.  
  2094.         vector float            vSinTwistA0;
  2095.         vector float            vSinTwistA1;
  2096.  
  2097.         vector float            vA;
  2098.         vector float            vB;
  2099.  
  2100.         vector float            vTransition;
  2101.         vector float            vZero = (vector float)(0);
  2102.         
  2103.         
  2104.         double                    fTemp;
  2105.         double                    baseAngle1;
  2106.         double                    baseAngle2;
  2107.  
  2108.         double                    fSinBaseAngle1;
  2109.         double                    fSinBaseAngle2;
  2110.         
  2111.         ////////////////////////////////////////////////////////////////////////////////
  2112.         // initialize a permute vector that, given input vectors:
  2113.         //
  2114.         //    X = x0 x1 x2 x3
  2115.         //    Y = y0 y1 y2 y3
  2116.         //
  2117.         // will generate
  2118.         //    Z = x0 x1 y0 y1
  2119.         ////////////////////////////////////////////////////////////////////////////////
  2120.         vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  2121.  
  2122.         ////////////////////////////////////////////////////////////////////////////////
  2123.         // initialize a permute vector that, given input vectors:
  2124.         //
  2125.         //    X = x0 x1 x2 x3
  2126.         //    Y = y0 y1 y2 y3
  2127.         //
  2128.         // will generate
  2129.         //    Z = x2 x3 y2 y3
  2130.         ////////////////////////////////////////////////////////////////////////////////
  2131.         vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  2132.         
  2133.         ////////////////////////////////////////////////////////////////////////////////
  2134.         // initialize a permute vector that, given input vectors:
  2135.         //
  2136.         //    X = x0 x1 x2 x3
  2137.         //    Y = y0 y1 y2 y3
  2138.         //
  2139.         // will generate
  2140.         //    Z = x1 x0 x3 y2
  2141.         ////////////////////////////////////////////////////////////////////////////////
  2142.         vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  2143.         
  2144.         ////////////////////////////////////////////////////////////////////////////////
  2145.         // vSinSignMultiplier is a vector used to create a vector in the form
  2146.         // -sin(x) sin(x) -sin(y) sin(y)
  2147.         ////////////////////////////////////////////////////////////////////////////////
  2148.         vSinSignMultiplier = (vector float)(-1, 1, -1, 1);
  2149.         
  2150.         ////////////////////////////////////////////////////////////////////////////////
  2151.         // perform a FFT on every row of the matrix
  2152.         ////////////////////////////////////////////////////////////////////////////////
  2153.         pRow = pData;
  2154.         
  2155.         for (i=rowCount-1; i>=0; i--) {
  2156.             result = FFTComplex(pRow+i*(colCount*2), colCount, 1);
  2157.             if (result != noErr) break;
  2158.         }
  2159.  
  2160.         if (result == noErr) {
  2161.             ////////////////////////////////////////////////////////////////////////////////
  2162.             // we now loop through all columns, two columns at a time, and perform column
  2163.             // ferrying FFTs on the columns.  We must also perform a twist multiply on
  2164.             // all entries, so we do this after we load in the columns, and before we
  2165.             // ferry them over to the temporary buffer
  2166.             ////////////////////////////////////////////////////////////////////////////////
  2167.  
  2168.             for (i=0; i<colCount/2; i++) {
  2169.             
  2170.                 ////////////////////////////////////////////////////////////////////////////////
  2171.                 // set up vectors for incremental updating of cos & sin vectors
  2172.                 //
  2173.                 // Given c = cos(w) and s = sin(w), if we want to find the cos and sin of w plus
  2174.                 // some small angle d, then we can do so by defining:
  2175.                 //    
  2176.                 // a = 2 * ((sin(d/2)) ^ 2)
  2177.                 // b = sin(d)
  2178.                 // 
  2179.                 // Then, we can calculate the cos and sin of the updated angle w+d as:
  2180.                 // 
  2181.                 // cos(w+d) = c - ac - bs
  2182.                 // sin(w+d) = s - as + bc
  2183.                 // 
  2184.                 // the vectors vA and vB contain these increment factors a and b.  Note that
  2185.                 // each outer loop iteration requires different increment angles.  Looking at
  2186.                 // the matrix, the angle multipliers that we use for our cos & sin twist
  2187.                 // multipliers look something like:
  2188.                 //
  2189.                 //        0/N        0/N        0/N        0/N        0/N        0/N        0/N    ...    0/N
  2190.                 //        0/N        1/N        2/N        3/N        4/N        5/N        6/N        
  2191.                 //        0/N        2/N        4/N        6/N        8/N        10/N    12/N    .
  2192.                 //        0/N        3/N        6/N        9/N        12/N    15/N    18/N    .    
  2193.                 //        0/N        4/N        8/N        12/N    16/N    20/N    24/N
  2194.                 //        .        .
  2195.                 //        .        .
  2196.                 //        0/N                                            ...            (N-1)(N-1)
  2197.                 //
  2198.                 // Since we're doing two columns at a time, the vA and vB vectors
  2199.                 // need to have two different sets of increment values.  For example, for
  2200.                 // the third and fourth columns (handled in the second time through the
  2201.                 // outer loop) each row increments by 2/N and 3/N.  Since we actually 
  2202.                 // have two sets of twist multiplier vectors, we skip a row for each, so
  2203.                 // the increment angle is doubled.  This helps reduce calculation dependencies
  2204.                 // and cuts the number of increment iterations in half, which helps reduce
  2205.                 // errors in the single-precision calculations used.
  2206.                 //        
  2207.                 ////////////////////////////////////////////////////////////////////////////////
  2208.  
  2209.                 baseAngle1 = 4*i*PI/(colCount*rowCount);
  2210.                 baseAngle2 = (2*(2*i+1)*PI)/(colCount*rowCount);
  2211.  
  2212.                 fSinBaseAngle1 = sin(baseAngle1);
  2213.                 fTemp = 2*fSinBaseAngle1*fSinBaseAngle1;
  2214.                 
  2215.                 ((float*)&vTransition)[0] = fTemp;
  2216.                 ((float*)&vTransition)[2] = sin(2*baseAngle1);
  2217.  
  2218.                 fSinBaseAngle2 = sin(baseAngle2);
  2219.                 fTemp = 2*fSinBaseAngle2*fSinBaseAngle2;
  2220.  
  2221.                 ((float*)&vTransition)[1] = fTemp;
  2222.                 ((float*)&vTransition)[3] = sin(2*baseAngle2);
  2223.  
  2224.                 vA = vec_mergeh(vTransition, vTransition);
  2225.                 vB = vec_mergel(vTransition, vTransition);
  2226.                 
  2227.                 vB = vec_madd(vB, vSinSignMultiplier, vZero);
  2228.  
  2229.                 ////////////////////////////////////////////////////////////////////////////////
  2230.                 //    Set up the initial twist multiplier vectors for the beginning of this
  2231.                 // column.  Values are calculated in the scalar domain, and then
  2232.                 // transferred to the vector domain via the vTransition vector.
  2233.                 ////////////////////////////////////////////////////////////////////////////////
  2234.                 
  2235.                 ((float*)&vTransition)[0] = 1;
  2236.                 
  2237.                 ((float*)&vTransition)[2] = cos(baseAngle1);
  2238.                 ((float*)&vTransition)[3] = cos(baseAngle2);
  2239.                 
  2240.                 vCosTwistA0 = vec_splat(vTransition, 0);
  2241.                 vCosTwistA1 = vec_mergel(vTransition, vTransition);
  2242.                 
  2243.                 vSinTwistA0 = vZero;
  2244.                 
  2245.                 ((float*)&vTransition)[2] = fSinBaseAngle1;
  2246.                 ((float*)&vTransition)[3] = fSinBaseAngle2;
  2247.                                         
  2248.                 vSinTwistA1 = vec_mergel(vTransition, vTransition);
  2249.                 vSinTwistA1 = vec_madd(vSinTwistA1, vSinSignMultiplier, vZero);
  2250.  
  2251.                 ////////////////////////////////////////////////////////////////////////////////
  2252.                 // initialize pointers in temporary buffer for storing copied columns.
  2253.                 ////////////////////////////////////////////////////////////////////////////////
  2254.             
  2255.                 pSplit1 = *(vector float**)rowBufferHandle;
  2256.                 pSplit2 = pSplit1 + rowCount / 2;
  2257.                 
  2258.                 ////////////////////////////////////////////////////////////////////////////////
  2259.                 // point at top of columns to be copied
  2260.                 ////////////////////////////////////////////////////////////////////////////////
  2261.  
  2262.                 pCurrentColumn = ((vector float*)pData) + i;
  2263.             
  2264.                 ////////////////////////////////////////////////////////////////////////////////
  2265.                 // loop through all rows in the current column, copying elements to the
  2266.                 // temporary buffer.  We load two rows at a time, and permute the vectors
  2267.                 // to create a single vector that contains the appropriate column elements
  2268.                 // from both rows.
  2269.                 ////////////////////////////////////////////////////////////////////////////////
  2270.  
  2271.                 for (j=0; j < rowCount/2; j++) {
  2272.  
  2273.                     vector float    vTwistedIn1, vTwistedIn2;
  2274.  
  2275.                     ////////////////////////////////////////////////////////////////////////////////
  2276.                     // read in two rows worth of vectors (two rows X two columns)
  2277.                     ////////////////////////////////////////////////////////////////////////////////
  2278.  
  2279.                     vIn1 = *pCurrentColumn;
  2280.                     pCurrentColumn += colCount/2;
  2281.                     vIn2 = *pCurrentColumn;
  2282.                     pCurrentColumn += colCount/2;
  2283.  
  2284.                     ////////////////////////////////////////////////////////////////////////////////
  2285.                     // twist multiply input vectors
  2286.                     ////////////////////////////////////////////////////////////////////////////////
  2287.  
  2288.                     vTwistedIn1 = vec_madd(vCosTwistA0, vIn1, vZero);
  2289.                     vTwistedIn1 = vec_madd(vSinTwistA0, vec_perm(vIn1, vIn1, vSwappedPerm), vTwistedIn1);
  2290.  
  2291.                     vTwistedIn2 = vec_madd(vCosTwistA1, vIn2, vZero);
  2292.                     vTwistedIn2 = vec_madd(vSinTwistA1, vec_perm(vIn2, vIn2, vSwappedPerm), vTwistedIn2);
  2293.  
  2294.                     ////////////////////////////////////////////////////////////////////////////////
  2295.                     // permute the vectors so that the two left column entries are in one vector
  2296.                     // and the two right column entries are in one vector
  2297.                     ////////////////////////////////////////////////////////////////////////////////
  2298.                                     
  2299.                     vOut1 = vec_perm(vTwistedIn1, vTwistedIn2, vMergeHiPairPerm);
  2300.                     vOut2 = vec_perm(vTwistedIn1, vTwistedIn2, vMergeLoPairPerm);
  2301.                     
  2302.                     ////////////////////////////////////////////////////////////////////////////////
  2303.                     // store the split columns to the appropriate buffers
  2304.                     ////////////////////////////////////////////////////////////////////////////////
  2305.  
  2306.                     *pSplit1++ = vOut1;
  2307.                     *pSplit2++ = vOut2;
  2308.  
  2309.                     ////////////////////////////////////////////////////////////////////////////////
  2310.                     // update sin & cos vectors for twist multiply
  2311.                     ////////////////////////////////////////////////////////////////////////////////
  2312.  
  2313.                     vCosTemp0 = vec_nmsub(vCosTwistA0, vA, vCosTwistA0);
  2314.                     vCosTemp0 = vec_nmsub(vSinTwistA0, vB, vCosTemp0);
  2315.  
  2316.                     vSinTwistA0 = vec_nmsub(vSinTwistA0, vA, vSinTwistA0);
  2317.                     vSinTwistA0 = vec_madd (vCosTwistA0, vB, vSinTwistA0);
  2318.  
  2319.                     vCosTwistA0 = vCosTemp0;
  2320.  
  2321.                     vCosTemp1 = vec_nmsub(vCosTwistA1, vA, vCosTwistA1);
  2322.                     vCosTemp1 = vec_nmsub(vSinTwistA1, vB, vCosTemp1);
  2323.  
  2324.                     vSinTwistA1 = vec_nmsub(vSinTwistA1, vA, vSinTwistA1);
  2325.                     vSinTwistA1 = vec_madd (vCosTwistA1, vB, vSinTwistA1);
  2326.  
  2327.                     vCosTwistA1 = vCosTemp1;
  2328.  
  2329.                 }
  2330.  
  2331.                 ////////////////////////////////////////////////////////////////////////////////
  2332.                 // perform FFTs on the two columns of data that we have copied to the temp
  2333.                 // buffer
  2334.                 ////////////////////////////////////////////////////////////////////////////////
  2335.  
  2336.                 pFFT1 = *(float **)rowBufferHandle;
  2337.                 pFFT2 = pFFT1 + 2*rowCount;
  2338.                 
  2339.                 result = FFTComplex(pFFT1, rowCount, 1);
  2340.                 if (result != noErr) break;
  2341.                 
  2342.                 result = FFTComplex(pFFT2, rowCount, 1);
  2343.                 if (result != noErr) break;
  2344.  
  2345.                 ////////////////////////////////////////////////////////////////////////////////
  2346.                 // point at the beginning of the two copied column buffers, and at the top
  2347.                 // of the columns in the matrix where we will store them back.
  2348.                 ////////////////////////////////////////////////////////////////////////////////
  2349.  
  2350.                 pSplit1 = *(vector float**)rowBufferHandle;
  2351.                 pSplit2 = pSplit1 + rowCount / 2;
  2352.                 pCurrentColumn = ((vector float*)pData) + i;
  2353.  
  2354.                 ////////////////////////////////////////////////////////////////////////////////
  2355.                 // loop through all of the column entries that are stored in the temp buffer,
  2356.                 // and merge them to be stored back into the columns of the matrix. 
  2357.                 ////////////////////////////////////////////////////////////////////////////////
  2358.  
  2359.                 for (j=0; j < rowCount/2; j++) {
  2360.                 
  2361.                     ////////////////////////////////////////////////////////////////////////////////
  2362.                     // get two vectors of column data
  2363.                     ////////////////////////////////////////////////////////////////////////////////
  2364.  
  2365.                     vIn1 = *pSplit1++;
  2366.                     vIn2 = *pSplit2++;
  2367.                     
  2368.                     ////////////////////////////////////////////////////////////////////////////////
  2369.                     // turn them into row vectors
  2370.                     ////////////////////////////////////////////////////////////////////////////////
  2371.  
  2372.                     vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  2373.                     vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  2374.                                     
  2375.                     ////////////////////////////////////////////////////////////////////////////////
  2376.                     // store row vectors back into the matrix
  2377.                     ////////////////////////////////////////////////////////////////////////////////
  2378.  
  2379.                     *pCurrentColumn = vOut1;
  2380.                     pCurrentColumn += colCount / 2;
  2381.                     *pCurrentColumn = vOut2;                
  2382.                     pCurrentColumn += colCount / 2;
  2383.                 }
  2384.                             
  2385.             
  2386.             }
  2387.                     
  2388.         }
  2389.  
  2390.     }
  2391.     if (rowBufferHandle) {
  2392.         DisposeHandle(rowBufferHandle);
  2393.     }
  2394.  
  2395.     return result;
  2396.  
  2397. }
  2398.  
  2399.  
  2400.  
  2401. ////////////////////////////////////////////////////////////////////////////////
  2402. //    fft_square_matrix
  2403. //
  2404. //    Performs a forward or inverse FFT on the data pointed to
  2405. // by pData.  If isign == -1, then a forward FFT is performed, otherwise an
  2406. // inverse FFT is performed.  The FFT is performed by doing a recursive matrix
  2407. // FFT.  The length of the data must be an even power of two, to ensure that
  2408. // the matrix is a square, which allows for a trivial transpose of the matrix
  2409. // to ensure that output data is in lexicographic order (or to transform input
  2410. // data into columnwise order, in the case of the inverse FFT).
  2411. ////////////////////////////////////////////////////////////////////////////////
  2412. static OSErr fft_square_matrix(float *pData, long length, long isign)
  2413. {
  2414.     long        pow;
  2415.     OSErr        result;
  2416.             
  2417.     pow = log2max(length);
  2418.     
  2419.     ////////////////////////////////////////////////////////////////////////////////
  2420.     // length must be an exact power of 2
  2421.     ////////////////////////////////////////////////////////////////////////////////
  2422.     if ((1 << pow) != length) {
  2423.         return paramErr;
  2424.     }
  2425.     
  2426.     ////////////////////////////////////////////////////////////////////////////////
  2427.     // length must be an even power of 2
  2428.     ////////////////////////////////////////////////////////////////////////////////
  2429.     if (pow & 1) {
  2430.         return paramErr;
  2431.     }
  2432.  
  2433.  
  2434.     if (isign == -1) {
  2435.  
  2436.         ////////////////////////////////////////////////////////////////////////////////
  2437.         // we are performing a forward FFT, so do a normal forward matrix FFT, which
  2438.         // will leave the data in columnwise order
  2439.         ////////////////////////////////////////////////////////////////////////////////
  2440.  
  2441.         result = fft_matrix_forward_columnwise(pData, length);
  2442.  
  2443.         if (result == noErr) {
  2444.  
  2445.             ////////////////////////////////////////////////////////////////////////////////
  2446.             // transpose the square matrix, so that data is no longer in columnwise order
  2447.             ////////////////////////////////////////////////////////////////////////////////
  2448.  
  2449.             SquareComplexTransposeVector(pData, 1<<(pow/2));
  2450.         }
  2451.  
  2452.     } else {
  2453.  
  2454.         ////////////////////////////////////////////////////////////////////////////////
  2455.         // transpose the square matrix of input data, to transform it into columnwise
  2456.         // order.
  2457.         ////////////////////////////////////////////////////////////////////////////////
  2458.         SquareComplexTransposeVector(pData, 1<<(pow/2));
  2459.  
  2460.         ////////////////////////////////////////////////////////////////////////////////
  2461.         // perform an inverse matrix FFT on the data, which expects the data to be
  2462.         // in columnwise order, and leaves the result in lexicographic order
  2463.         ////////////////////////////////////////////////////////////////////////////////
  2464.  
  2465.         result = fft_matrix_inverse_columnwise(pData, length);    
  2466.  
  2467.     }
  2468.  
  2469.     return result;
  2470.  
  2471. }
  2472.  
  2473. #pragma mark -
  2474. #pragma mark C O M P L E X   F F T
  2475.  
  2476. ////////////////////////////////////////////////////////////////////////////////
  2477. // fft_altivec
  2478. //
  2479. //    Performs a forward or inverse FFT on the complex signal data
  2480. // pointed to by pData. pTempBuffer must point to a buffer that is of equal
  2481. // length as the signal pointed to by pData, and which will be overwritten by
  2482. // the routine.  If isign == -1, then a forward FFT is performed.  Otherwise
  2483. // an inverse FFT is performed.
  2484. //
  2485. // requirements:
  2486. //
  2487. //    - length must be an exact power of 2 
  2488. //    - pData and pTempBuffer must be 16-byte aligned
  2489. //    - signal length must be at least 16, because of vector sizes and
  2490. //        implementation details.
  2491. //
  2492. ////////////////////////////////////////////////////////////////////////////////
  2493.  
  2494. static OSErr fft_altivec(float *pData, float *pTempBuffer, unsigned long len, long isign)
  2495. {
  2496.     long                     j, i;
  2497.     float                     *srcPtr, *dstPtr, *tmp;
  2498.     long                     pow, root, trig;
  2499.     float                    *sinCosTable;
  2500.      OSErr                    result = noErr;   
  2501.  
  2502.     vector float            vZero;
  2503.     vector unsigned char    vSwappedPerm;
  2504.     vector unsigned char    vMergeHiPairPerm;
  2505.     vector unsigned char    vMergeLoPairPerm;
  2506.     vector unsigned char    vCosPermute;
  2507.     vector signed long         vSinNegSinSelect;
  2508.     vector unsigned char    vSinPermute;
  2509.  
  2510.     vector float             vCSLoad1;
  2511.     vector float             vCSLoad2;
  2512.     
  2513.     vector float             vNegCSLoad1;
  2514.     vector float             vNegCSLoad2;
  2515.  
  2516.     vector float             vCosA1;
  2517.     vector float             vSinA1;
  2518.  
  2519.     vector float             vCosA2;
  2520.     vector float             vSinA2;
  2521.  
  2522.     vector float             vIn1;
  2523.     vector float             vIn2;
  2524.     vector float             vIn3;
  2525.     vector float             vIn4;
  2526.     
  2527.     vector float             vDiffA1;
  2528.     vector float             vDiffA2;
  2529.  
  2530.     vector float             vSumA1;
  2531.     vector float             vSumA2;
  2532.     
  2533.     vector float             vSwappedDiffA1;
  2534.     vector float             vSwappedDiffA2;
  2535.     
  2536.     vector float             vButterflyA1;
  2537.     vector float             vButterflyA2;
  2538.  
  2539.     vector float             vInLoB1, vInHiB1;
  2540.     vector float             vInLoB2, vInHiB2;
  2541.     vector float             vSinB1, vSinB2;
  2542.     vector float             vCosB1, vCosB2;
  2543.  
  2544.     vector float             vDiffB1, vDiffB2;
  2545.     vector float             vSwappedDiffB1, vSwappedDiffB2;
  2546.     
  2547.     vector float             vResultLoB1, vResultLoB2;
  2548.     vector float             vResultHiB1, vResultHiB2;
  2549.  
  2550.     vector float             vCSLoadB1;
  2551.     vector float             vNegSinB1;
  2552.  
  2553.     vector float             vCSLoadB2;
  2554.     vector float             vNegSinB2;
  2555.  
  2556.  
  2557.     vector float            *pInVec1, *pInVec2, *pInVec3, *pInVec4;
  2558.     vector float            *pOutVec1, *pOutVec2, *pOutVec3, *pOutVec4;
  2559.  
  2560.     vector float            vInLo1, vInLo2;
  2561.     vector float            vInHi1, vInHi2;
  2562.     vector float            vResultLo1, vResultLo2;
  2563.     vector float            vResultHi1, vResultHi2;
  2564.  
  2565.     vector float            vSinSignMultiplier;
  2566.  
  2567.     vector float            vTransitionFloatVector;
  2568.     vector float            vInverseDivideMultiplier;
  2569.  
  2570.     
  2571.     ////////////////////////////////////////////////////////////////////////////////
  2572.     // calculate log2(len)
  2573.     ////////////////////////////////////////////////////////////////////////////////    
  2574.     pow = log2max(len);
  2575.     
  2576.     ////////////////////////////////////////////////////////////////////////////////
  2577.     // length must be an exact power of 2
  2578.     ////////////////////////////////////////////////////////////////////////////////
  2579.     if ((1 << pow) != len) {
  2580.         return paramErr;
  2581.     }
  2582.     
  2583.     ////////////////////////////////////////////////////////////////////////////////
  2584.     // data must be 16-byte aligned because of vector load/store requirements
  2585.     ////////////////////////////////////////////////////////////////////////////////
  2586.     if (((long)pData) & 0x0F) {
  2587.         return paramErr;
  2588.     }
  2589.  
  2590.     ////////////////////////////////////////////////////////////////////////////////
  2591.     // temp buffer must be 16-byte aligned because of vector load/store requirements
  2592.     ////////////////////////////////////////////////////////////////////////////////
  2593.     if (((long)pTempBuffer) & 0x0F) {
  2594.         return paramErr;
  2595.     }
  2596.  
  2597.  
  2598.     ////////////////////////////////////////////////////////////////////////////////
  2599.     // make sure that the sin cos lookup table is for the current fft length
  2600.     ////////////////////////////////////////////////////////////////////////////////
  2601.     if (len != gSinCosTableSize) result = InitFFTSinCos(len);
  2602.     
  2603.     if (result == noErr) {
  2604.  
  2605.         ////////////////////////////////////////////////////////////////////////////////
  2606.         // initialize a zero vector
  2607.         ////////////////////////////////////////////////////////////////////////////////
  2608.         vZero = (vector float)(0);
  2609.  
  2610.         ////////////////////////////////////////////////////////////////////////////////
  2611.         // initialize a permute vector that, given input vectors:
  2612.         //
  2613.         //    X = x0 x1 x2 x3
  2614.         //    Y = y0 y1 y2 y3
  2615.         //
  2616.         // will generate
  2617.         //    Z = x1 x0 x3 y2
  2618.         ////////////////////////////////////////////////////////////////////////////////
  2619.         vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  2620.  
  2621.         ////////////////////////////////////////////////////////////////////////////////
  2622.         // initialize a permute vector that, given input vectors:
  2623.         //
  2624.         //    X = x0 x1 x2 x3
  2625.         //    Y = y0 y1 y2 y3
  2626.         //
  2627.         // will generate
  2628.         //    Z = x0 x1 y0 y1
  2629.         ////////////////////////////////////////////////////////////////////////////////
  2630.         vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  2631.  
  2632.         ////////////////////////////////////////////////////////////////////////////////
  2633.         // initialize a permute vector that, given input vectors:
  2634.         //
  2635.         //    X = x0 x1 x2 x3
  2636.         //    Y = y0 y1 y2 y3
  2637.         //
  2638.         // will generate
  2639.         //    Z = x2 x3 y2 y3
  2640.         ////////////////////////////////////////////////////////////////////////////////
  2641.         vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  2642.  
  2643.         ////////////////////////////////////////////////////////////////////////////////
  2644.         // initialize a permute vector that, given input vectors:
  2645.         //
  2646.         //    X = x0 x1 x2 x3
  2647.         //    Y = y0 y1 y2 y3
  2648.         //
  2649.         // will generate
  2650.         //    Z = x0 x0 x2 x2
  2651.         ////////////////////////////////////////////////////////////////////////////////
  2652.         vCosPermute = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 8, 9, 10, 11);
  2653.  
  2654.         ////////////////////////////////////////////////////////////////////////////////
  2655.         // initialize permute, select, and 
  2656.         // multiplier vectors based on whether
  2657.         // we are doing a forward or inverse
  2658.         // fft.
  2659.         ////////////////////////////////////////////////////////////////////////////////
  2660.         if (isign < 0) {
  2661.             ////////////////////////////////////////////////////////////////////////////////
  2662.             // initialize a multiplier vector that will
  2663.             // negate the second and fourth float
  2664.             // elements.
  2665.             ////////////////////////////////////////////////////////////////////////////////
  2666.             vSinSignMultiplier = (vector float)(1, -1, 1, -1);
  2667.  
  2668.             ////////////////////////////////////////////////////////////////////////////////
  2669.             // initialize a select vector that, given input vectors:
  2670.             //
  2671.             //    X = x0 x1 x2 x3
  2672.             //    Y = y0 y1 y2 y3
  2673.             //
  2674.             // will generate
  2675.             //    Z = x0 y1 x2 y3
  2676.             ////////////////////////////////////////////////////////////////////////////////
  2677.             vSinNegSinSelect = (vector signed long)(0, -1, 0, -1);                
  2678.             
  2679.             ////////////////////////////////////////////////////////////////////////////////
  2680.             // initialize a permute vector that, given input vectors:
  2681.             //
  2682.             //    X = x0 x1 x2 x3
  2683.             //    Y = y0 y1 y2 y3
  2684.             //
  2685.             // will generate
  2686.             //    Z = x1 y1 x3 y3
  2687.             ////////////////////////////////////////////////////////////////////////////////
  2688.             vSinPermute = (vector unsigned char)(4, 5, 6, 7, 20, 21, 22, 23, 12, 13, 14, 15, 28, 29, 30, 31);
  2689.             
  2690.         } else {
  2691.             ////////////////////////////////////////////////////////////////////////////////
  2692.             // initialize a multiplier vector that will
  2693.             // negate the first and third float
  2694.             // elements.
  2695.             ////////////////////////////////////////////////////////////////////////////////
  2696.             vSinSignMultiplier = (vector float)(-1, 1, -1, 1);
  2697.  
  2698.             ////////////////////////////////////////////////////////////////////////////////
  2699.             // initialize a select vector that, given input vectors:
  2700.             //
  2701.             //    X = x0 x1 x2 x3
  2702.             //    Y = y0 y1 y2 y3
  2703.             //
  2704.             // will generate
  2705.             //    Z = y0 x1 y2 x3
  2706.             ////////////////////////////////////////////////////////////////////////////////
  2707.             vSinNegSinSelect = (vector signed long)(-1, 0, -1, 0);        
  2708.  
  2709.             ////////////////////////////////////////////////////////////////////////////////
  2710.             // initialize a permute vector that, given input vectors:
  2711.             //
  2712.             //    X = x0 x1 x2 x3
  2713.             //    Y = y0 y1 y2 y3
  2714.             //
  2715.             // will generate
  2716.             //    Z = y1 x1 y3 x3
  2717.             ////////////////////////////////////////////////////////////////////////////////
  2718.             vSinPermute = (vector unsigned char)(20, 21, 22, 23, 4, 5, 6, 7, 28, 29, 30, 31, 12, 13, 14, 15);
  2719.             
  2720.         }
  2721.  
  2722.         ////////////////////////////////////////////////////////////////////////////////
  2723.         // init trig counter, for indexing output vectors 
  2724.         ////////////////////////////////////////////////////////////////////////////////
  2725.         trig = 1;
  2726.                 
  2727.         ////////////////////////////////////////////////////////////////////////////////
  2728.         // start with data as source and temp buffer as destination
  2729.         ////////////////////////////////////////////////////////////////////////////////
  2730.         srcPtr = pData;
  2731.         dstPtr = pTempBuffer;
  2732.  
  2733.         ////////////////////////////////////////////////////////////////////////////////
  2734.         // create pointer to start of cos/sin table for array indexing
  2735.         ////////////////////////////////////////////////////////////////////////////////
  2736.         sinCosTable = *(float**)gSinCosTableHandle;
  2737.  
  2738.         ////////////////////////////////////////////////////////////////////////////////
  2739.         // initialize root to zero.  Root is used as an index into the sin & cos table
  2740.         ////////////////////////////////////////////////////////////////////////////////
  2741.         root = 0;
  2742.  
  2743.         do {
  2744.             ////////////////////////////////////////////////////////////////////////////////
  2745.             // load sin & cos
  2746.             ////////////////////////////////////////////////////////////////////////////////
  2747.             vCSLoad1 = *(vector float*)&sinCosTable[root];
  2748.             vCSLoad2 = *(vector float*)&sinCosTable[(len/2)+root];
  2749.             
  2750.             ////////////////////////////////////////////////////////////////////////////////
  2751.             // create negative sin & cos
  2752.             ////////////////////////////////////////////////////////////////////////////////
  2753.             vNegCSLoad1 = vec_sub(vZero, vCSLoad1);
  2754.             vNegCSLoad2 = vec_sub(vZero, vCSLoad2);
  2755.  
  2756.             ////////////////////////////////////////////////////////////////////////////////
  2757.             // create vector
  2758.             //
  2759.             //     vCosA1 = cos(root*pi/len) cos(root*pi/len) cos((root+2)*pi/len) cos((root+2)*pi/len)
  2760.             ////////////////////////////////////////////////////////////////////////////////
  2761.             vCosA1 = vec_perm(vCSLoad1, vCSLoad1, vCosPermute);
  2762.  
  2763.             ////////////////////////////////////////////////////////////////////////////////
  2764.             // create vector
  2765.             //
  2766.             //     vSinA1 = sin(root*pi/len) -sin(root*pi/len) sin((root+2)*pi/len) -sin((root+2)*pi/len)
  2767.             //
  2768.             // or
  2769.             //
  2770.             //     vSinA1 = -sin(root*pi/len) sin(root*pi/len) -sin((root+2)*pi/len) sin((root+2)*pi/len)
  2771.             //
  2772.             // depending on whether we are doing a forward or inverse fft
  2773.             ////////////////////////////////////////////////////////////////////////////////
  2774.             vSinA1 = vec_perm(vCSLoad1, vNegCSLoad1, vSinPermute);
  2775.  
  2776.             ////////////////////////////////////////////////////////////////////////////////
  2777.             // create vector
  2778.             //
  2779.             //     vCosA2 = cos(pi/2 + root*pi/len) cos(pi/2 + root*pi/len) cos(pi/2 + (root+2)*pi/len) cos(pi/2 + (root+2)*pi/len)
  2780.             ////////////////////////////////////////////////////////////////////////////////
  2781.             vCosA2 = vec_perm(vCSLoad2, vCSLoad2, vCosPermute);
  2782.  
  2783.  
  2784.             ////////////////////////////////////////////////////////////////////////////////
  2785.             // create vector
  2786.             //
  2787.             //     vSinA1 = sin(pi/2 + root*pi/len) -sin(pi/2 + root*pi/len) sin(pi/2 + (root+2)*pi/len) -sin(pi/2 + (root+2)*pi/len)
  2788.             //
  2789.             // or
  2790.             //
  2791.             //     vSinA1 = -sin(pi/2 + root*pi/len) sin(pi/2 + root*pi/len) -sin(pi/2 + (root+2)*pi/len) sin(pi/2 + (root+2)*pi/len)
  2792.             //
  2793.             // depending on whether we are doing a forward or inverse fft
  2794.             ////////////////////////////////////////////////////////////////////////////////
  2795.             vSinA2 = vec_perm(vCSLoad2, vNegCSLoad2, vSinPermute);
  2796.  
  2797.             ////////////////////////////////////////////////////////////////////////////////
  2798.             // load four input vectors for calculating butterflies
  2799.             ////////////////////////////////////////////////////////////////////////////////
  2800.             vIn1 = *(vector float*)srcPtr;
  2801.             vIn2 = *(vector float*)&srcPtr[len];
  2802.             vIn3 = *(vector float*)&srcPtr[len/2];
  2803.             vIn4 = *(vector float*)&srcPtr[len + len/2];
  2804.  
  2805.             ////////////////////////////////////////////////////////////////////////////////
  2806.             // calculate four butterflies of input vectors (two from vIn1 and vIn2, two
  2807.             // from vIn3 and vIn4).
  2808.             ////////////////////////////////////////////////////////////////////////////////
  2809.             
  2810.             vDiffA1 = vec_sub(vIn1, vIn2);
  2811.             vDiffA2 = vec_sub(vIn3, vIn4);
  2812.  
  2813.             vSumA1 = vec_add(vIn1, vIn2);
  2814.             vSumA2 = vec_add(vIn3, vIn4);
  2815.             
  2816.             vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  2817.             vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  2818.             
  2819.             vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  2820.             vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  2821.  
  2822.             vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  2823.             vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  2824.  
  2825.             ////////////////////////////////////////////////////////////////////////////////
  2826.             // results of butterflies from first stage are input to butterflies
  2827.             // of second stage
  2828.             ////////////////////////////////////////////////////////////////////////////////
  2829.  
  2830.             vInLoB1 = vec_perm(vSumA1, vButterflyA1, vMergeHiPairPerm);
  2831.             vInLoB2 = vec_perm(vSumA1, vButterflyA1, vMergeLoPairPerm);
  2832.             
  2833.             vInHiB1 = vec_perm(vSumA2, vButterflyA2, vMergeHiPairPerm);
  2834.             vInHiB2 = vec_perm(vSumA2, vButterflyA2, vMergeLoPairPerm);
  2835.  
  2836.             ////////////////////////////////////////////////////////////////////////////////
  2837.             // load sin & cos and generate sin, cos vectors for second-stage butterfly
  2838.             ////////////////////////////////////////////////////////////////////////////////
  2839.  
  2840.             vCSLoadB1 = *(vector float*)&sinCosTable[2*root];
  2841.             vSinB1 = vec_splat(vCSLoadB1, 1);
  2842.             vCosB1 = vec_splat(vCSLoadB1, 0);
  2843.             vNegSinB1 = vec_sub(vZero, vSinB1);
  2844.  
  2845.             vSinB1 = vec_sel(vSinB1, vNegSinB1, (vector unsigned long)vSinNegSinSelect);
  2846.  
  2847.             vCSLoadB2 = *(vector float*)&sinCosTable[2*root+4];
  2848.             vSinB2 = vec_splat(vCSLoadB2, 1);
  2849.             vCosB2 = vec_splat(vCSLoadB2, 0);
  2850.             vNegSinB2 = vec_sub(vZero, vSinB2);
  2851.  
  2852.             vSinB2 = vec_sel(vSinB2, vNegSinB2, (vector unsigned long)vSinNegSinSelect);
  2853.             
  2854.             vDiffB1 = vec_sub(vInLoB1, vInHiB1);
  2855.             vDiffB2 = vec_sub(vInLoB2, vInHiB2);
  2856.             
  2857.             vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  2858.             vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);
  2859.             
  2860.             vResultLoB1 = vec_add(vInLoB1, vInHiB1);
  2861.             vResultLoB2 = vec_add(vInLoB2, vInHiB2);
  2862.  
  2863.             vResultHiB1 = vec_madd(vCosB1, vDiffB1, vZero);
  2864.             vResultHiB1 = vec_madd(vSinB1, vSwappedDiffB1, vResultHiB1);
  2865.  
  2866.             vResultHiB2 = vec_madd(vCosB2, vDiffB2, vZero);
  2867.             vResultHiB2 = vec_madd(vSinB2, vSwappedDiffB2, vResultHiB2);
  2868.                     
  2869.             ////////////////////////////////////////////////////////////////////////////////
  2870.             // store results of second stage butterfly
  2871.             ////////////////////////////////////////////////////////////////////////////////
  2872.  
  2873.             *(vector float*)dstPtr             = vResultLoB1;
  2874.             *(vector float*)(dstPtr+4)         = vResultHiB1;
  2875.             *(vector float*)(dstPtr+8)        = vResultLoB2;
  2876.             *(vector float*)(dstPtr+12)     = vResultHiB2;
  2877.  
  2878.             ////////////////////////////////////////////////////////////////////////////////
  2879.             // update pointers and sin/cos root index for next time through loop
  2880.             ////////////////////////////////////////////////////////////////////////////////
  2881.             srcPtr += 4;         
  2882.             dstPtr += 16;
  2883.             root += 4;        
  2884.             
  2885.         } while (root < len/2);
  2886.         
  2887.         
  2888.         ////////////////////////////////////////////////////////////////////////////////
  2889.         // for second step, source is temp buffer, and destination is original
  2890.         // data buffer
  2891.         ////////////////////////////////////////////////////////////////////////////////
  2892.         srcPtr = pTempBuffer;
  2893.         dstPtr = pData;
  2894.  
  2895.         trig *= 4;
  2896.         
  2897.         ////////////////////////////////////////////////////////////////////////////////
  2898.         // In the ping-pong FFT, for each power of two, butterflies are calculated
  2899.         // using all elements in the data.  To eliminate load/store operations, we
  2900.         // perform a "double butterfly", essentially doing two steps of butterflies
  2901.         // for each pass through the data.  So, we need to do pow/2 passes through
  2902.         // the data.  We've already done the first pass, so we must do (pow-2/2) loops
  2903.         // through the data at this point.
  2904.         ////////////////////////////////////////////////////////////////////////////////
  2905.         for(i = (pow-2)/2; i > 0; i--) {
  2906.                         
  2907.             ////////////////////////////////////////////////////////////////////////////////
  2908.             // initialize source pointers
  2909.             ////////////////////////////////////////////////////////////////////////////////
  2910.             pInVec1 = (vector float*)srcPtr;
  2911.             pInVec2 = (vector float*)&srcPtr[len];
  2912.             pInVec3 = (vector float*)&srcPtr[len/2];    
  2913.             pInVec4 = (vector float*)&srcPtr[len + len/2];        
  2914.                                 
  2915.             root = 0;
  2916.  
  2917.             ////////////////////////////////////////////////////////////////////////////////
  2918.             // if this is the last time through the loop, and the length is an even power
  2919.             // of two, but an odd power of four, then the source data is the input buffer, 
  2920.             // and the dest data would be the temp buffer.  However, for the last step,
  2921.             // the input data and output data indices for the butterflies are the same, so
  2922.             // we can write directly back into the source data.  This eliminates the need
  2923.             // to copy from the temp buffer back to the original buffer to return the
  2924.             // fft result data.
  2925.             ////////////////////////////////////////////////////////////////////////////////
  2926.             if (i == 1) {
  2927.             
  2928.                 ////////////////////////////////////////////////////////////////////////////////
  2929.                 // if the length is an even power of two, then this is the last iteration that
  2930.                 // we will go through.  Otherwise we'll do an additional single butterfly
  2931.                 // pass through the data.
  2932.                 ////////////////////////////////////////////////////////////////////////////////
  2933.                 if (!(pow & 1)) {
  2934.                     ////////////////////////////////////////////////////////////////////////////////
  2935.                     // we're copying from original buffer back into original buffer
  2936.                     ////////////////////////////////////////////////////////////////////////////////
  2937.                     if ((pow & 3) == 2) {
  2938.                         dstPtr = srcPtr;
  2939.                     }
  2940.                     
  2941.                 
  2942.                     ////////////////////////////////////////////////////////////////////////////////
  2943.                     // load sin & cos for first butterfly, and generate sin & cos vectors
  2944.                     ////////////////////////////////////////////////////////////////////////////////
  2945.                     vCSLoad1 = *(vector float*)&sinCosTable[root];
  2946.                     
  2947.                     vCosA1 = vec_splat(vCSLoad1, 0);
  2948.                     vCosA2 = vec_splat(vCSLoad1, 1);
  2949.  
  2950.                     vSinA1 = vec_madd(vCosA2, vSinSignMultiplier, vZero);
  2951.                     
  2952.                     vCosA2 = vec_sub(vZero, vCosA2);
  2953.                     
  2954.                     vSinA2 = vec_madd(vCosA1, vSinSignMultiplier, vZero);
  2955.  
  2956.                     ////////////////////////////////////////////////////////////////////////////////
  2957.                     // set up output data pointers
  2958.                     ////////////////////////////////////////////////////////////////////////////////
  2959.  
  2960.                     pOutVec1 = ((vector float*)dstPtr)+root;
  2961.                     pOutVec2 = ((vector float*)(dstPtr + trig*4))+root;
  2962.                     pOutVec3 = ((vector float*)(dstPtr + trig*2))+root;
  2963.                     pOutVec4 = ((vector float*)(dstPtr + trig*6))+root;
  2964.  
  2965.                     if (isign > 0) {
  2966.                                                 
  2967.                         ////////////////////////////////////////////////////////////////////////////////
  2968.                         // we are performing an inverse FFT, so we need to divide the final results by
  2969.                         // the length of the FFT input data.  Since there is no vector divide, we
  2970.                         // create a float vector of 1/N, and then do a multiply of the data before
  2971.                         // we store it back.
  2972.                         //
  2973.                         // We use a transition vector to go from the scalar to vector domain.
  2974.                         // We don't store directly to our multiplier vector, so that the compiler can
  2975.                         // more easily optimize the multiplier vector to be register-based
  2976.                         // rather than stack-based.
  2977.                         ////////////////////////////////////////////////////////////////////////////////
  2978.                         ((float*)&vTransitionFloatVector)[0] = (double)1/(double)len;
  2979.                         
  2980.                         vInverseDivideMultiplier = vec_splat(vTransitionFloatVector, 0);
  2981.                         
  2982.                         for(j = trig/4; j > 0; j--) {
  2983.  
  2984.                             ////////////////////////////////////////////////////////////////////////////////
  2985.                             // load in four input vectors
  2986.                             ////////////////////////////////////////////////////////////////////////////////
  2987.                             vIn1 = *pInVec1++;
  2988.                             vIn2 = *pInVec2++;
  2989.                             vIn3 = *pInVec3++;
  2990.                             vIn4 = *pInVec4++;
  2991.                             
  2992.                             ////////////////////////////////////////////////////////////////////////////////
  2993.                             // calculate butterflies for first stage
  2994.                             ////////////////////////////////////////////////////////////////////////////////
  2995.                             
  2996.                             vDiffA1 = vec_sub(vIn1, vIn2);
  2997.                             vDiffA2 = vec_sub(vIn3, vIn4);
  2998.  
  2999.                             vSumA1 = vec_add(vIn1, vIn2);
  3000.                             vSumA2 = vec_add(vIn3, vIn4);
  3001.                             
  3002.                             vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3003.                             vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3004.                             
  3005.                             vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3006.                             vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3007.  
  3008.                             vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3009.                             vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3010.                             
  3011.                             ////////////////////////////////////////////////////////////////////////////////
  3012.                             // calculate butterflies for second stage
  3013.                             ////////////////////////////////////////////////////////////////////////////////
  3014.  
  3015.                             vDiffB1 = vec_sub(vSumA1, vSumA2);
  3016.                             vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3017.                             
  3018.                             vResultLoB1 = vec_add(vSumA1, vSumA2);
  3019.                             vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3020.  
  3021.                             vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3022.                             vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3023.  
  3024.                             vResultHiB1 = vec_madd(vCosA1, vDiffB1, vZero);
  3025.                             vResultHiB1 = vec_madd(vSinA1, vSwappedDiffB1, vResultHiB1);
  3026.  
  3027.                             vResultHiB2 = vec_madd(vCosA1, vDiffB2, vZero);
  3028.                             vResultHiB2 = vec_madd(vSinA1, vSwappedDiffB2, vResultHiB2);
  3029.  
  3030.                             ////////////////////////////////////////////////////////////////////////////////
  3031.                             // since we're performing an inverse FFT, we now divide each element by len
  3032.                             // before we store it back.
  3033.                             ////////////////////////////////////////////////////////////////////////////////
  3034.                         
  3035.                             vResultLoB1 = vec_madd(vResultLoB1, vInverseDivideMultiplier, vZero);
  3036.                             vResultLoB2 = vec_madd(vResultLoB2, vInverseDivideMultiplier, vZero);
  3037.                             vResultHiB1 = vec_madd(vResultHiB1, vInverseDivideMultiplier, vZero);
  3038.                             vResultHiB2 = vec_madd(vResultHiB2, vInverseDivideMultiplier, vZero);
  3039.  
  3040.                             ////////////////////////////////////////////////////////////////////////////////
  3041.                             // For speed, we unroll the loop once. This allows the compiler to better
  3042.                             // optimize the object code.  Because the compiler doesn't move loads and
  3043.                             // stores around each other, the code is faster if we explicitly move the
  3044.                             // second set of input vector loads above the first set of output vector 
  3045.                             // stores, which allows the compiler to better optimize the dispatch of
  3046.                             // the input loads.
  3047.                             ////////////////////////////////////////////////////////////////////////////////
  3048.  
  3049.                             ////////////////////////////////////////////////////////////////////////////////
  3050.                             // load input vectors for second half of unrolled loop
  3051.                             ////////////////////////////////////////////////////////////////////////////////
  3052.  
  3053.                             vIn1 = *pInVec1++;
  3054.                             vIn2 = *pInVec2++;
  3055.                             vIn3 = *pInVec3++;
  3056.                             vIn4 = *pInVec4++;
  3057.  
  3058.                             ////////////////////////////////////////////////////////////////////////////////
  3059.                             // store second stage butterfly output of first half of unrolled loop to 
  3060.                             // dest buffer
  3061.                             ////////////////////////////////////////////////////////////////////////////////
  3062.  
  3063.                             *pOutVec1++ = vResultLoB1;
  3064.                             *pOutVec2++ = vResultHiB1;
  3065.                             *pOutVec3++ = vResultLoB2;
  3066.                             *pOutVec4++ = vResultHiB2;
  3067.                         
  3068.                             ////////////////////////////////////////////////////////////////////////////////
  3069.                             // calculate butterflies for first stage
  3070.                             ////////////////////////////////////////////////////////////////////////////////
  3071.                             
  3072.                             vDiffA1 = vec_sub(vIn1, vIn2);
  3073.                             vDiffA2 = vec_sub(vIn3, vIn4);
  3074.  
  3075.                             vSumA1 = vec_add(vIn1, vIn2);
  3076.                             vSumA2 = vec_add(vIn3, vIn4);
  3077.                             
  3078.                             vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3079.                             vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3080.                             
  3081.                             vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3082.                             vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3083.  
  3084.                             vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3085.                             vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3086.                             
  3087.                             ////////////////////////////////////////////////////////////////////////////////
  3088.                             // calculate butterflies for second stage
  3089.                             ////////////////////////////////////////////////////////////////////////////////
  3090.                             
  3091.                             vDiffB1 = vec_sub(vSumA1, vSumA2);
  3092.                             vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3093.                             
  3094.                             vResultLoB1 = vec_add(vSumA1, vSumA2);
  3095.                             vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3096.  
  3097.                             vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3098.                             vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3099.  
  3100.                             vResultHiB1 = vec_madd(vCosA1, vDiffB1, vZero);
  3101.                             vResultHiB1 = vec_madd(vSinA1, vSwappedDiffB1, vResultHiB1);
  3102.  
  3103.                             vResultHiB2 = vec_madd(vCosA1, vDiffB2, vZero);
  3104.                             vResultHiB2 = vec_madd(vSinA1, vSwappedDiffB2, vResultHiB2);
  3105.  
  3106.                             ////////////////////////////////////////////////////////////////////////////////
  3107.                             // since we're performing an inverse FFT, we now divide each element by len
  3108.                             // before we store it back.
  3109.                             ////////////////////////////////////////////////////////////////////////////////
  3110.                         
  3111.                             vResultLoB1 = vec_madd(vResultLoB1, vInverseDivideMultiplier, vZero);
  3112.                             vResultLoB2 = vec_madd(vResultLoB2, vInverseDivideMultiplier, vZero);
  3113.                             vResultHiB1 = vec_madd(vResultHiB1, vInverseDivideMultiplier, vZero);
  3114.                             vResultHiB2 = vec_madd(vResultHiB2, vInverseDivideMultiplier, vZero);
  3115.  
  3116.                             ////////////////////////////////////////////////////////////////////////////////
  3117.                             // store second stage butterfly output of second half of unrolled loop to
  3118.                             // dest buffer
  3119.                             ////////////////////////////////////////////////////////////////////////////////
  3120.  
  3121.                             *pOutVec1++ = vResultLoB1;
  3122.                             *pOutVec2++ = vResultHiB1;
  3123.                             *pOutVec3++ = vResultLoB2;
  3124.                             *pOutVec4++ = vResultHiB2;                
  3125.                             
  3126.                         }
  3127.  
  3128.                     } else {
  3129.                                                 
  3130.                         ////////////////////////////////////////////////////////////////////////////////
  3131.                         // perform normal butterfly calculations for forward FFT
  3132.                         ////////////////////////////////////////////////////////////////////////////////
  3133.                                                                                                                         
  3134.                         for(j = trig/4; j > 0; j--) {
  3135.  
  3136.                             ////////////////////////////////////////////////////////////////////////////////
  3137.                             // load in four input vectors
  3138.                             ////////////////////////////////////////////////////////////////////////////////
  3139.                             vIn1 = *pInVec1++;
  3140.                             vIn2 = *pInVec2++;
  3141.                             vIn3 = *pInVec3++;
  3142.                             vIn4 = *pInVec4++;
  3143.                             
  3144.                             ////////////////////////////////////////////////////////////////////////////////
  3145.                             // calculate butterflies for first stage
  3146.                             ////////////////////////////////////////////////////////////////////////////////
  3147.                             
  3148.                             vDiffA1 = vec_sub(vIn1, vIn2);
  3149.                             vDiffA2 = vec_sub(vIn3, vIn4);
  3150.  
  3151.                             vSumA1 = vec_add(vIn1, vIn2);
  3152.                             vSumA2 = vec_add(vIn3, vIn4);
  3153.                             
  3154.                             vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3155.                             vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3156.                             
  3157.                             vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3158.                             vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3159.  
  3160.                             vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3161.                             vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3162.                             
  3163.                             ////////////////////////////////////////////////////////////////////////////////
  3164.                             // calculate butterflies for second stage
  3165.                             ////////////////////////////////////////////////////////////////////////////////
  3166.  
  3167.                             vDiffB1 = vec_sub(vSumA1, vSumA2);
  3168.                             vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3169.                             
  3170.                             vResultLoB1 = vec_add(vSumA1, vSumA2);
  3171.                             vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3172.  
  3173.                             vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3174.                             vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3175.  
  3176.                             vResultHiB1 = vec_madd(vCosA1, vDiffB1, vZero);
  3177.                             vResultHiB1 = vec_madd(vSinA1, vSwappedDiffB1, vResultHiB1);
  3178.  
  3179.                             vResultHiB2 = vec_madd(vCosA1, vDiffB2, vZero);
  3180.                             vResultHiB2 = vec_madd(vSinA1, vSwappedDiffB2, vResultHiB2);
  3181.  
  3182.                             ////////////////////////////////////////////////////////////////////////////////
  3183.                             // For speed, we unroll the loop once. This allows the compiler to better
  3184.                             // optimize the object code.  Because the compiler doesn't move loads and
  3185.                             // stores around each other, the code is faster if we explicitly move the
  3186.                             // second set of input vector loads above the first set of output vector 
  3187.                             // stores, which allows the compiler to better optimize the dispatch of
  3188.                             // the input loads.
  3189.                             ////////////////////////////////////////////////////////////////////////////////
  3190.  
  3191.                             ////////////////////////////////////////////////////////////////////////////////
  3192.                             // load input vectors for second half of
  3193.                             // unrolled loop
  3194.                             ////////////////////////////////////////////////////////////////////////////////
  3195.  
  3196.                             vIn1 = *pInVec1++;
  3197.                             vIn2 = *pInVec2++;
  3198.                             vIn3 = *pInVec3++;
  3199.                             vIn4 = *pInVec4++;
  3200.  
  3201.                             ////////////////////////////////////////////////////////////////////////////////
  3202.                             // store second stage butterfly output of  first half of unrolled loop to
  3203.                             // dest buffer
  3204.                             ////////////////////////////////////////////////////////////////////////////////
  3205.  
  3206.                             *pOutVec1++ = vResultLoB1;
  3207.                             *pOutVec2++ = vResultHiB1;
  3208.                             *pOutVec3++ = vResultLoB2;
  3209.                             *pOutVec4++ = vResultHiB2;
  3210.                         
  3211.                             ////////////////////////////////////////////////////////////////////////////////
  3212.                             // calculate butterflies for first stage
  3213.                             ////////////////////////////////////////////////////////////////////////////////
  3214.                             
  3215.                             vDiffA1 = vec_sub(vIn1, vIn2);
  3216.                             vDiffA2 = vec_sub(vIn3, vIn4);
  3217.  
  3218.                             vSumA1 = vec_add(vIn1, vIn2);
  3219.                             vSumA2 = vec_add(vIn3, vIn4);
  3220.                             
  3221.                             vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3222.                             vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3223.                             
  3224.                             vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3225.                             vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3226.  
  3227.                             vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3228.                             vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3229.                             
  3230.                             ////////////////////////////////////////////////////////////////////////////////
  3231.                             // calculate butterflies for second stage
  3232.                             ////////////////////////////////////////////////////////////////////////////////
  3233.                             
  3234.                             vDiffB1 = vec_sub(vSumA1, vSumA2);
  3235.                             vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3236.                             
  3237.                             vResultLoB1 = vec_add(vSumA1, vSumA2);
  3238.                             vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3239.  
  3240.                             vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3241.                             vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3242.  
  3243.                             vResultHiB1 = vec_madd(vCosA1, vDiffB1, vZero);
  3244.                             vResultHiB1 = vec_madd(vSinA1, vSwappedDiffB1, vResultHiB1);
  3245.  
  3246.                             vResultHiB2 = vec_madd(vCosA1, vDiffB2, vZero);
  3247.                             vResultHiB2 = vec_madd(vSinA1, vSwappedDiffB2, vResultHiB2);
  3248.  
  3249.                             ////////////////////////////////////////////////////////////////////////////////
  3250.                             // store second stage butterfly output of second half of unrolled loop to
  3251.                             // dest buffer
  3252.                             ////////////////////////////////////////////////////////////////////////////////
  3253.  
  3254.                             *pOutVec1++ = vResultLoB1;
  3255.                             *pOutVec2++ = vResultHiB1;
  3256.                             *pOutVec3++ = vResultLoB2;
  3257.                             *pOutVec4++ = vResultHiB2;                
  3258.                             
  3259.                         }
  3260.  
  3261.                     }
  3262.  
  3263.                     return result;
  3264.                 
  3265.                 }
  3266.             }
  3267.  
  3268.             ////////////////////////////////////////////////////////////////////////////////
  3269.             // a special case for what would be the first iteration through the
  3270.             // "while (root < len/2)" loop below, for which root = 0.  When root is
  3271.             // 0, the sin cos table loads for root are the same as the sin cos table
  3272.             // loads for 2*root, so we special-case this instance to avoid the extra load and
  3273.             // permutes to setup the sin & cos vectors.
  3274.             ////////////////////////////////////////////////////////////////////////////////
  3275.  
  3276.             ////////////////////////////////////////////////////////////////////////////////
  3277.             // load sin & cos for first butterfly, and generate sin & cos vectors
  3278.             ////////////////////////////////////////////////////////////////////////////////
  3279.             vCSLoad1 = *(vector float*)&sinCosTable[root];
  3280.             
  3281.             vCosA1 = vec_splat(vCSLoad1, 0);
  3282.             vCosA2 = vec_splat(vCSLoad1, 1);
  3283.  
  3284.             vSinA1 = vec_madd(vCosA2, vSinSignMultiplier, vZero);
  3285.             
  3286.             vCosA2 = vec_sub(vZero, vCosA2);
  3287.             
  3288.             vSinA2 = vec_madd(vCosA1, vSinSignMultiplier, vZero);
  3289.  
  3290.             ////////////////////////////////////////////////////////////////////////////////
  3291.             // set up output data pointers
  3292.             ////////////////////////////////////////////////////////////////////////////////
  3293.  
  3294.             pOutVec1 = ((vector float*)dstPtr)+root;
  3295.             pOutVec2 = ((vector float*)(dstPtr + trig*4))+root;
  3296.             pOutVec3 = ((vector float*)(dstPtr + trig*2))+root;
  3297.             pOutVec4 = ((vector float*)(dstPtr + trig*6))+root;
  3298.             
  3299.             for(j = trig/4; j > 0; j--) {
  3300.  
  3301.                 ////////////////////////////////////////////////////////////////////////////////
  3302.                 // load in four input vectors
  3303.                 ////////////////////////////////////////////////////////////////////////////////
  3304.                 
  3305.                 vIn1 = *pInVec1++;
  3306.                 vIn2 = *pInVec2++;
  3307.                 vIn3 = *pInVec3++;
  3308.                 vIn4 = *pInVec4++;
  3309.                 
  3310.                 ////////////////////////////////////////////////////////////////////////////////
  3311.                 // calculate butterflies for first stage
  3312.                 ////////////////////////////////////////////////////////////////////////////////
  3313.                 
  3314.                 vDiffA1 = vec_sub(vIn1, vIn2);
  3315.                 vDiffA2 = vec_sub(vIn3, vIn4);
  3316.  
  3317.                 vSumA1 = vec_add(vIn1, vIn2);
  3318.                 vSumA2 = vec_add(vIn3, vIn4);
  3319.                 
  3320.                 vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3321.                 vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3322.                 
  3323.                 vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3324.                 vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3325.  
  3326.                 vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3327.                 vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3328.                 
  3329.                 ////////////////////////////////////////////////////////////////////////////////
  3330.                 // calculate butterflies for second stage
  3331.                 ////////////////////////////////////////////////////////////////////////////////
  3332.  
  3333.                 vDiffB1 = vec_sub(vSumA1, vSumA2);
  3334.                 vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3335.                 
  3336.                 vResultLoB1 = vec_add(vSumA1, vSumA2);
  3337.                 vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3338.  
  3339.                 vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3340.                 vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3341.  
  3342.                 vResultHiB1 = vec_madd(vCosA1, vDiffB1, vZero);
  3343.                 vResultHiB1 = vec_madd(vSinA1, vSwappedDiffB1, vResultHiB1);
  3344.  
  3345.                 vResultHiB2 = vec_madd(vCosA1, vDiffB2, vZero);
  3346.                 vResultHiB2 = vec_madd(vSinA1, vSwappedDiffB2, vResultHiB2);
  3347.  
  3348.                 ////////////////////////////////////////////////////////////////////////////////
  3349.                 // For speed, we unroll the loop once. This allows the compiler to better
  3350.                 // optimize the object code.  Because the compiler doesn't move loads and
  3351.                 // stores around each other, the code is faster if we explicitly move the
  3352.                 // second set of input vector loads above the first set of output vector 
  3353.                 // stores, which allows the compiler to better optimize the dispatch of
  3354.                 // the input loads.
  3355.                 ////////////////////////////////////////////////////////////////////////////////
  3356.  
  3357.  
  3358.                 ////////////////////////////////////////////////////////////////////////////////
  3359.                 // load input vectors for second half of unrolled loop
  3360.                 ////////////////////////////////////////////////////////////////////////////////
  3361.  
  3362.                 vIn1 = *pInVec1++;
  3363.                 vIn2 = *pInVec2++;
  3364.                 vIn3 = *pInVec3++;
  3365.                 vIn4 = *pInVec4++;
  3366.  
  3367.                 ////////////////////////////////////////////////////////////////////////////////
  3368.                 // store second stage butterfly output of first half of unrolled loop to 
  3369.                 // dest buffer
  3370.                 ////////////////////////////////////////////////////////////////////////////////
  3371.  
  3372.                 *pOutVec1++ = vResultLoB1;
  3373.                 *pOutVec2++ = vResultHiB1;
  3374.                 *pOutVec3++ = vResultLoB2;
  3375.                 *pOutVec4++ = vResultHiB2;
  3376.             
  3377.                 ////////////////////////////////////////////////////////////////////////////////
  3378.                 // calculate butterflies for first stage
  3379.                 ////////////////////////////////////////////////////////////////////////////////
  3380.                 
  3381.                 vDiffA1 = vec_sub(vIn1, vIn2);
  3382.                 vDiffA2 = vec_sub(vIn3, vIn4);
  3383.  
  3384.                 vSumA1 = vec_add(vIn1, vIn2);
  3385.                 vSumA2 = vec_add(vIn3, vIn4);
  3386.                 
  3387.                 vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3388.                 vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3389.                 
  3390.                 vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3391.                 vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3392.  
  3393.                 vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3394.                 vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3395.                 
  3396.                 ////////////////////////////////////////////////////////////////////////////////
  3397.                 // calculate butterflies for second stage
  3398.                 ////////////////////////////////////////////////////////////////////////////////
  3399.                 
  3400.                 vDiffB1 = vec_sub(vSumA1, vSumA2);
  3401.                 vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3402.                 
  3403.                 vResultLoB1 = vec_add(vSumA1, vSumA2);
  3404.                 vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3405.  
  3406.                 vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3407.                 vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3408.  
  3409.                 vResultHiB1 = vec_madd(vCosA1, vDiffB1, vZero);
  3410.                 vResultHiB1 = vec_madd(vSinA1, vSwappedDiffB1, vResultHiB1);
  3411.  
  3412.                 vResultHiB2 = vec_madd(vCosA1, vDiffB2, vZero);
  3413.                 vResultHiB2 = vec_madd(vSinA1, vSwappedDiffB2, vResultHiB2);
  3414.  
  3415.                 ////////////////////////////////////////////////////////////////////////////////
  3416.                 // store second stage butterfly output of second half of unrolled loop to 
  3417.                 // dest buffer
  3418.                 ////////////////////////////////////////////////////////////////////////////////
  3419.  
  3420.                 *pOutVec1++ = vResultLoB1;
  3421.                 *pOutVec2++ = vResultHiB1;
  3422.                 *pOutVec3++ = vResultLoB2;
  3423.                 *pOutVec4++ = vResultHiB2;                
  3424.                 
  3425.             }
  3426.  
  3427.             ////////////////////////////////////////////////////////////////////////////////
  3428.             // update root value for sin & cos load
  3429.             ////////////////////////////////////////////////////////////////////////////////
  3430.             root += 2*trig;
  3431.  
  3432.             
  3433.             while (root < len/2) {      
  3434.  
  3435.                 ////////////////////////////////////////////////////////////////////////////////
  3436.                 // load sin & cos
  3437.                 ////////////////////////////////////////////////////////////////////////////////
  3438.                 vCSLoad1 = *(vector float*)&sinCosTable[root];
  3439.                 
  3440.                 ////////////////////////////////////////////////////////////////////////////////
  3441.                 // create vector
  3442.                 //
  3443.                 //     vCosA1 = cos(root*pi/len) cos(root*pi/len) cos((root+2)*pi/len) cos((root+2)*pi/len)
  3444.                 ////////////////////////////////////////////////////////////////////////////////
  3445.                 vCosA1 = vec_splat(vCSLoad1, 0);
  3446.                 
  3447.                 
  3448.                 ////////////////////////////////////////////////////////////////////////////////
  3449.                 // create vector
  3450.                 //
  3451.                 //     vCosA2 = -cos(pi/2 + root*pi/len) -cos(pi/2 + root*pi/len) -cos(pi/2 + (root+2)*pi/len) -cos(pi/2 + (root+2)*pi/len)
  3452.                 ////////////////////////////////////////////////////////////////////////////////
  3453.                 vCosA2 = vec_splat(vCSLoad1, 1);
  3454.  
  3455.                 ////////////////////////////////////////////////////////////////////////////////
  3456.                 // create vector
  3457.                 //
  3458.                 //     vSinA1 = sin(root*pi/len) -sin(root*pi/len) sin((root+2)*pi/len) -sin((root+2)*pi/len)
  3459.                 //
  3460.                 // or
  3461.                 //
  3462.                 //     vSinA1 = -sin(root*pi/len) sin(root*pi/len) -sin((root+2)*pi/len) sin((root+2)*pi/len)
  3463.                 //
  3464.                 // depending on whether we are doing a forward or inverse fft
  3465.                 ////////////////////////////////////////////////////////////////////////////////
  3466.                 vSinA1 = vec_madd(vCosA2, vSinSignMultiplier, vZero);
  3467.                 
  3468.                 ////////////////////////////////////////////////////////////////////////////////
  3469.                 // turn negative cos to positive cos
  3470.                 ////////////////////////////////////////////////////////////////////////////////
  3471.                 vCosA2 = vec_sub(vZero, vCosA2);
  3472.                 
  3473.                 ////////////////////////////////////////////////////////////////////////////////
  3474.                 // create vector
  3475.                 //
  3476.                 //     vSinA1 = sin(pi/2 + root*pi/len) -sin(pi/2 + root*pi/len) sin(pi/2 + (root+2)*pi/len) -sin(pi/2 + (root+2)*pi/len)
  3477.                 //
  3478.                 // or
  3479.                 //
  3480.                 //     vSinA1 = -sin(pi/2 + root*pi/len) sin(pi/2 + root*pi/len) -sin(pi/2 + (root+2)*pi/len) sin(pi/2 + (root+2)*pi/len)
  3481.                 //
  3482.                 // depending on whether we are doing a forward or inverse fft
  3483.                 ////////////////////////////////////////////////////////////////////////////////
  3484.                 vSinA2 = vec_madd(vCosA1, vSinSignMultiplier, vZero);
  3485.  
  3486.                 ////////////////////////////////////////////////////////////////////////////////
  3487.                 // load sin & cos and generate sin, cos vectors for second-stage butterfly
  3488.                 ////////////////////////////////////////////////////////////////////////////////
  3489.                 vCSLoadB1 = *(vector float*)&sinCosTable[2*root];
  3490.                 vSinB1 = vec_splat(vCSLoadB1, 1);
  3491.                 vCosB1 = vec_splat(vCSLoadB1, 0);
  3492.  
  3493.                 vNegSinB1 = vec_sub(vZero, vSinB1);
  3494.  
  3495.                 vSinB1 = vec_sel(vSinB1, vNegSinB1, (vector unsigned long)vSinNegSinSelect);
  3496.  
  3497.                 ////////////////////////////////////////////////////////////////////////////////
  3498.                 // set up output data pointers
  3499.                 ////////////////////////////////////////////////////////////////////////////////
  3500.  
  3501.                 pOutVec1 = ((vector float*)dstPtr)+root;
  3502.                 pOutVec2 = ((vector float*)(dstPtr + trig*4))+root;
  3503.                 pOutVec3 = ((vector float*)(dstPtr + trig*2))+root;
  3504.                 pOutVec4 = ((vector float*)(dstPtr + trig*6))+root;
  3505.                 
  3506.  
  3507.                 for(j = trig/4; j > 0; j--) {
  3508.  
  3509.                     ////////////////////////////////////////////////////////////////////////////////
  3510.                     // load in four input vectors
  3511.                     ////////////////////////////////////////////////////////////////////////////////
  3512.                     vIn1 = *pInVec1++;
  3513.                     vIn2 = *pInVec2++;
  3514.                     vIn3 = *pInVec3++;
  3515.                     vIn4 = *pInVec4++;
  3516.  
  3517.                     ////////////////////////////////////////////////////////////////////////////////
  3518.                     // calculate butterflies for first stage
  3519.                     ////////////////////////////////////////////////////////////////////////////////
  3520.  
  3521.                     vDiffA1 = vec_sub(vIn1, vIn2);
  3522.                     vDiffA2 = vec_sub(vIn3, vIn4);
  3523.  
  3524.                     vSumA1 = vec_add(vIn1, vIn2);
  3525.                     vSumA2 = vec_add(vIn3, vIn4);
  3526.  
  3527.                     vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3528.                     vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3529.  
  3530.                     vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3531.                     vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3532.  
  3533.                     vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3534.                     vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3535.  
  3536.                     ////////////////////////////////////////////////////////////////////////////////
  3537.                     // calculate butterflies for second stage
  3538.                     ////////////////////////////////////////////////////////////////////////////////
  3539.  
  3540.                     vDiffB1 = vec_sub(vSumA1, vSumA2);
  3541.                     vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3542.  
  3543.                     vResultLoB1 = vec_add(vSumA1, vSumA2);
  3544.                     vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3545.  
  3546.                     vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3547.                     vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3548.  
  3549.                     vResultHiB1 = vec_madd(vCosB1, vDiffB1, vZero);
  3550.                     vResultHiB1 = vec_madd(vSinB1, vSwappedDiffB1, vResultHiB1);
  3551.  
  3552.                     vResultHiB2 = vec_madd(vCosB1, vDiffB2, vZero);
  3553.                     vResultHiB2 = vec_madd(vSinB1, vSwappedDiffB2, vResultHiB2);
  3554.  
  3555.                     ////////////////////////////////////////////////////////////////////////////////
  3556.                     // For speed, we unroll the loop once. This allows the compiler to better
  3557.                     // optimize the object code.  Because the compiler doesn't move loads and
  3558.                     // stores around each other, the code is faster if we explicitly move the
  3559.                     // second set of input vector loads above the first set of output vector 
  3560.                     // stores, which allows the compiler to better optimize the dispatch of
  3561.                     // the input loads.
  3562.                     ////////////////////////////////////////////////////////////////////////////////
  3563.  
  3564.                     ////////////////////////////////////////////////////////////////////////////////
  3565.                     // load input vectors for second half of
  3566.                     // unrolled loop
  3567.                     ////////////////////////////////////////////////////////////////////////////////
  3568.  
  3569.                     vIn1 = *pInVec1++;
  3570.                     vIn2 = *pInVec2++;
  3571.                     vIn3 = *pInVec3++;
  3572.                     vIn4 = *pInVec4++;
  3573.  
  3574.                     ////////////////////////////////////////////////////////////////////////////////
  3575.                     // store second stage butterfly output of first half of unrolled loop to
  3576.                     // dest buffer
  3577.                     ////////////////////////////////////////////////////////////////////////////////
  3578.  
  3579.                     *pOutVec1++ = vResultLoB1;
  3580.                     *pOutVec2++ = vResultHiB1;
  3581.                     *pOutVec3++ = vResultLoB2;
  3582.                     *pOutVec4++ = vResultHiB2;
  3583.  
  3584.                     ////////////////////////////////////////////////////////////////////////////////
  3585.                     // calculate butterflies for first stage
  3586.                     ////////////////////////////////////////////////////////////////////////////////
  3587.  
  3588.                     vDiffA1 = vec_sub(vIn1, vIn2);
  3589.                     vDiffA2 = vec_sub(vIn3, vIn4);
  3590.  
  3591.                     vSumA1 = vec_add(vIn1, vIn2);
  3592.                     vSumA2 = vec_add(vIn3, vIn4);
  3593.  
  3594.                     vSwappedDiffA1 = vec_perm(vDiffA1, vDiffA1, vSwappedPerm);
  3595.                     vSwappedDiffA2 = vec_perm(vDiffA2, vDiffA2, vSwappedPerm);
  3596.  
  3597.                     vButterflyA1 = vec_madd(vDiffA1, vCosA1, vZero);
  3598.                     vButterflyA1 = vec_madd(vSwappedDiffA1, vSinA1, vButterflyA1);
  3599.  
  3600.                     vButterflyA2 = vec_madd(vDiffA2, vCosA2, vZero);
  3601.                     vButterflyA2 = vec_madd(vSwappedDiffA2, vSinA2, vButterflyA2);
  3602.  
  3603.                     ////////////////////////////////////////////////////////////////////////////////
  3604.                     // calculate butterflies for second stage
  3605.                     ////////////////////////////////////////////////////////////////////////////////
  3606.  
  3607.                     vDiffB1 = vec_sub(vSumA1, vSumA2);
  3608.                     vDiffB2 = vec_sub(vButterflyA1, vButterflyA2);
  3609.  
  3610.                     vResultLoB1 = vec_add(vSumA1, vSumA2);
  3611.                     vResultLoB2 = vec_add(vButterflyA1, vButterflyA2);
  3612.  
  3613.                     vSwappedDiffB1 = vec_perm(vDiffB1, vDiffB1, vSwappedPerm);
  3614.                     vSwappedDiffB2 = vec_perm(vDiffB2, vDiffB2, vSwappedPerm);                
  3615.  
  3616.                     vResultHiB1 = vec_madd(vCosB1, vDiffB1, vZero);
  3617.                     vResultHiB1 = vec_madd(vSinB1, vSwappedDiffB1, vResultHiB1);
  3618.  
  3619.                     vResultHiB2 = vec_madd(vCosB1, vDiffB2, vZero);
  3620.                     vResultHiB2 = vec_madd(vSinB1, vSwappedDiffB2, vResultHiB2);
  3621.  
  3622.                     ////////////////////////////////////////////////////////////////////////////////
  3623.                     // store second stage butterfly output of second half of unrolled loop to
  3624.                     // dest buffer
  3625.                     ////////////////////////////////////////////////////////////////////////////////
  3626.  
  3627.                     *pOutVec1++ = vResultLoB1;
  3628.                     *pOutVec2++ = vResultHiB1;
  3629.                     *pOutVec3++ = vResultLoB2;
  3630.                     *pOutVec4++ = vResultHiB2;
  3631.  
  3632.                     
  3633.                 }
  3634.  
  3635.                 root += 2*trig;
  3636.  
  3637.             }
  3638.  
  3639.             trig *= 4;
  3640.             tmp = dstPtr; dstPtr = srcPtr; srcPtr = tmp;
  3641.  
  3642.         }
  3643.  
  3644.  
  3645.         ////////////////////////////////////////////////////////////////////////////////
  3646.         // if the length is an odd power of two, then we need to do one more
  3647.         // single-butterfly pass through the data.  Since we know that the sin and cos
  3648.         // values for this last pass are 0 and 1, we can simplify the butterfly
  3649.         // calculations to adds and subtracts.
  3650.         ////////////////////////////////////////////////////////////////////////////////
  3651.  
  3652.         if (pow & 1) {
  3653.             
  3654.             ////////////////////////////////////////////////////////////////////////////////
  3655.             // output always goes back to original input data buffer        
  3656.             ////////////////////////////////////////////////////////////////////////////////
  3657.                         
  3658.             pOutVec1 = (vector float*)pData;
  3659.             
  3660.             ////////////////////////////////////////////////////////////////////////////////
  3661.             // set source pointer to load from whatever the last step's output data was
  3662.             ////////////////////////////////////////////////////////////////////////////////
  3663.  
  3664.             if (pow & 2) {
  3665.                 pInVec1 = (vector float*)pTempBuffer;
  3666.             } else {
  3667.                 pInVec1 = (vector float*)pData;
  3668.             }
  3669.                     
  3670.             ////////////////////////////////////////////////////////////////////////////////
  3671.             // set second input and output vectors to point half-way 
  3672.             ////////////////////////////////////////////////////////////////////////////////
  3673.             pInVec2 = pInVec1+(len/4);    
  3674.             pOutVec2 = pOutVec1+(len/4);
  3675.  
  3676.             if (isign > 0) {
  3677.                                         
  3678.                 ////////////////////////////////////////////////////////////////////////////////
  3679.                 // we are performing an inverse FFT, so we need to divide the final results by
  3680.                 // the length of the FFT input data.  Since there is no vector divide, we create a
  3681.                 // float vector of 1/N, and then do a multiply of the data before we store it
  3682.                 // back.
  3683.                 //
  3684.                 // We use a transition vector to go from the scalar to vector domain.  We don't store
  3685.                 // directly to our multiplier vector, so that the compiler can more easily optimize
  3686.                 // the multiplier vector to be register-based rather than stack-based.
  3687.                 ////////////////////////////////////////////////////////////////////////////////
  3688.                 ((float*)&vTransitionFloatVector)[0] = (double)1/(double)len;
  3689.                 
  3690.                 vInverseDivideMultiplier = vec_splat(vTransitionFloatVector, 0);
  3691.  
  3692.                 for(j = trig/8; j > 0; j--) {
  3693.  
  3694.                     ////////////////////////////////////////////////////////////////////////////////
  3695.                     // load four input vectors
  3696.                     ////////////////////////////////////////////////////////////////////////////////
  3697.                     vInLo1 = *pInVec1++;
  3698.                     vInHi1 = *pInVec2++;
  3699.                     vInLo2 = *pInVec1++;
  3700.                     vInHi2 = *pInVec2++;
  3701.                     
  3702.                     ////////////////////////////////////////////////////////////////////////////////
  3703.                     // calc simplified butterflies, multiplying by inverse correction factor. 
  3704.                     ////////////////////////////////////////////////////////////////////////////////
  3705.  
  3706.                     vInLo1 = vec_madd(vInLo1, vInverseDivideMultiplier, vZero);
  3707.                     
  3708.                     vResultHi1 = vec_nmsub(vInHi1, vInverseDivideMultiplier, vInLo1);
  3709.                     vResultLo1 = vec_madd(vInHi1, vInverseDivideMultiplier, vInLo1);
  3710.  
  3711.                     vInLo2 = vec_madd(vInLo2, vInverseDivideMultiplier, vZero);
  3712.                     
  3713.                     vResultHi2 = vec_nmsub(vInHi2, vInverseDivideMultiplier, vInLo2);
  3714.                     vResultLo2 = vec_madd(vInHi2, vInverseDivideMultiplier, vInLo2);
  3715.  
  3716.                     ////////////////////////////////////////////////////////////////////////////////
  3717.                     // load input vectors for second half of unrolled loop
  3718.                     ////////////////////////////////////////////////////////////////////////////////
  3719.                 
  3720.                     vInLo1 = *pInVec1++;
  3721.                     vInHi1 = *pInVec2++;
  3722.                     vInLo2 = *pInVec1++;
  3723.                     vInHi2 = *pInVec2++;
  3724.  
  3725.                     ////////////////////////////////////////////////////////////////////////////////
  3726.                     // store results from first half of unrolled loop
  3727.                     ////////////////////////////////////////////////////////////////////////////////
  3728.             
  3729.                     *pOutVec1++ = vResultLo1;
  3730.                     *pOutVec2++ = vResultHi1;
  3731.                     *pOutVec1++ = vResultLo2;
  3732.                     *pOutVec2++ = vResultHi2;
  3733.  
  3734.  
  3735.                     ////////////////////////////////////////////////////////////////////////////////
  3736.                     // calc simplified butterflies, multiplying by inverse multiplier factor.
  3737.                     ////////////////////////////////////////////////////////////////////////////////
  3738.  
  3739.                     vInLo1 = vec_madd(vInLo1, vInverseDivideMultiplier, vZero);
  3740.                     
  3741.                     vResultHi1 = vec_nmsub(vInHi1, vInverseDivideMultiplier, vInLo1);
  3742.                     vResultLo1 = vec_madd(vInHi1, vInverseDivideMultiplier, vInLo1);
  3743.  
  3744.                     vInLo2 = vec_madd(vInLo2, vInverseDivideMultiplier, vZero);
  3745.                     
  3746.                     vResultHi2 = vec_nmsub(vInHi2, vInverseDivideMultiplier, vInLo2);
  3747.                     vResultLo2 = vec_madd(vInHi2, vInverseDivideMultiplier, vInLo2);
  3748.  
  3749.                     ////////////////////////////////////////////////////////////////////////////////
  3750.                     // store results from second half of unrolled loop
  3751.                     ////////////////////////////////////////////////////////////////////////////////
  3752.             
  3753.                     *pOutVec1++ = vResultLo1;
  3754.                     *pOutVec2++ = vResultHi1;
  3755.                     *pOutVec1++ = vResultLo2;
  3756.                     *pOutVec2++ = vResultHi2;
  3757.                     
  3758.                 }
  3759.                 
  3760.             } else {
  3761.             
  3762.                 for(j = trig/8; j > 0; j--) {
  3763.  
  3764.                     ////////////////////////////////////////////////////////////////////////////////
  3765.                     // load four input vectors
  3766.                     ////////////////////////////////////////////////////////////////////////////////
  3767.                     vInLo1 = *pInVec1++;
  3768.                     vInHi1 = *pInVec2++;
  3769.                     vInLo2 = *pInVec1++;
  3770.                     vInHi2 = *pInVec2++;
  3771.                     
  3772.                     ////////////////////////////////////////////////////////////////////////////////
  3773.                     // calc simplified butterflies 
  3774.                     ////////////////////////////////////////////////////////////////////////////////
  3775.                     vResultHi1 = vec_sub(vInLo1, vInHi1);
  3776.                     vResultLo1 = vec_add(vInLo1, vInHi1);
  3777.                             
  3778.                     vResultHi2 = vec_sub(vInLo2, vInHi2);                
  3779.                     vResultLo2 = vec_add(vInLo2, vInHi2);
  3780.  
  3781.                     ////////////////////////////////////////////////////////////////////////////////
  3782.                     // load input vectors for second half of unrolled loop
  3783.                     ////////////////////////////////////////////////////////////////////////////////
  3784.                 
  3785.                     vInLo1 = *pInVec1++;
  3786.                     vInHi1 = *pInVec2++;
  3787.                     vInLo2 = *pInVec1++;
  3788.                     vInHi2 = *pInVec2++;
  3789.  
  3790.                     ////////////////////////////////////////////////////////////////////////////////
  3791.                     // store results from first half of unrolled loop
  3792.                     ////////////////////////////////////////////////////////////////////////////////
  3793.             
  3794.                     *pOutVec1++ = vResultLo1;
  3795.                     *pOutVec2++ = vResultHi1;
  3796.                     *pOutVec1++ = vResultLo2;
  3797.                     *pOutVec2++ = vResultHi2;
  3798.  
  3799.  
  3800.                     ////////////////////////////////////////////////////////////////////////////////
  3801.                     // calc simplified butterflies 
  3802.                     ////////////////////////////////////////////////////////////////////////////////
  3803.  
  3804.                     vResultHi1 = vec_sub(vInLo1, vInHi1);
  3805.                     vResultLo1 = vec_add(vInLo1, vInHi1);
  3806.             
  3807.                     vResultHi2 = vec_sub(vInLo2, vInHi2);                
  3808.                     vResultLo2 = vec_add(vInLo2, vInHi2);
  3809.  
  3810.                     ////////////////////////////////////////////////////////////////////////////////
  3811.                     // store results from second half of unrolled loop
  3812.                     ////////////////////////////////////////////////////////////////////////////////
  3813.             
  3814.                     *pOutVec1++ = vResultLo1;
  3815.                     *pOutVec2++ = vResultHi1;
  3816.                     *pOutVec1++ = vResultLo2;
  3817.                     *pOutVec2++ = vResultHi2;
  3818.                     
  3819.                 }
  3820.             
  3821.             }
  3822.         }
  3823.  
  3824.     }
  3825.     
  3826.  
  3827.     return result;
  3828.     
  3829. }
  3830.  
  3831.  
  3832. ////////////////////////////////////////////////////////////////////////////////
  3833. // fft_scalar
  3834. //
  3835. // Ping-pong Stockham FFT
  3836. //
  3837. //    Performs a forward or inverse FFT on the complex signal data
  3838. // pointed to by pData. pTempBuffer must point to a buffer that is of equal
  3839. // length as the signal pointed to by pData, and which will be overwritten by
  3840. // the routine.  If isign == -1, then a forward FFT is performed.  Otherwise
  3841. // an inverse FFT is performed.
  3842. //
  3843. // requirements:
  3844. //
  3845. //    - length must be an exact power of 2 
  3846. //
  3847. ////////////////////////////////////////////////////////////////////////////////
  3848. static OSErr fft_scalar(float *pData, float *tempbuff, unsigned long len, long isign)
  3849. {
  3850.     long     j, i;
  3851.     float     c, s, tre, tim, *srcDataPtr, *dstDataPtr, *tmp;
  3852.     double     inverseDivideMultiplier;
  3853.     long     pow, root, trig;
  3854.     OSErr     result = noErr;
  3855.     float    *sinCosTable;
  3856.  
  3857.     ////////////////////////////////////////////////////////////////////////////////
  3858.     // calculate log2(len)
  3859.     ////////////////////////////////////////////////////////////////////////////////
  3860.     
  3861.     pow = log2max(len);
  3862.     
  3863.     ////////////////////////////////////////////////////////////////////////////////
  3864.     // length must be an exact power of 2    
  3865.     ////////////////////////////////////////////////////////////////////////////////
  3866.     
  3867.     if ((1 << pow) != len) return paramErr;
  3868.  
  3869.     ////////////////////////////////////////////////////////////////////////////////
  3870.     // make sure that the sin cos lookup table is for the current fft length
  3871.     ////////////////////////////////////////////////////////////////////////////////
  3872.     if (len != gSinCosTableSize) result = InitFFTSinCos(len);
  3873.  
  3874.     if (result == noErr) {
  3875.  
  3876.         ////////////////////////////////////////////////////////////////////////////////
  3877.         // initialize "trig" step for destination index
  3878.         ////////////////////////////////////////////////////////////////////////////////
  3879.  
  3880.         trig = 1;
  3881.         
  3882.         ////////////////////////////////////////////////////////////////////////////////
  3883.         // Start with data as source, and temp buffer as destination
  3884.         ////////////////////////////////////////////////////////////////////////////////
  3885.  
  3886.         srcDataPtr = pData;
  3887.         dstDataPtr = tempbuff;
  3888.  
  3889.         ////////////////////////////////////////////////////////////////////////////////
  3890.         // get pointer to start of sin/cos table handle for array reference
  3891.         ////////////////////////////////////////////////////////////////////////////////
  3892.         
  3893.         sinCosTable = *(float**)gSinCosTableHandle;
  3894.  
  3895.         for(i = pow-1; i > 0; i--) {
  3896.  
  3897.             root = 0;
  3898.             while(root < len/2) {
  3899.  
  3900.                 ////////////////////////////////////////////////////////////////////////////////
  3901.                 // load cos and sin values for current root value.
  3902.                 ////////////////////////////////////////////////////////////////////////////////
  3903.  
  3904.                 c = sinCosTable[2*root];
  3905.                 s = isign*sinCosTable[2*root+1];
  3906.  
  3907.                 for(j = trig; j > 0; j--) {
  3908.  
  3909.                     ////////////////////////////////////////////////////////////////////////////////
  3910.                     // calculate butterflies.  For inputs:
  3911.                     // [re0, im0] [re1, im1]
  3912.                     //
  3913.                     // we calculate:
  3914.                     //
  3915.                     // out0 = [re0+re1, im0+im1]
  3916.                     //
  3917.                     // out1 = [ cos * (re0-re1) - sin * (im0-im1),
  3918.                     //            sin * (re0-re1) + cos * (im0-im1) ]
  3919.                     //
  3920.                     ////////////////////////////////////////////////////////////////////////////////
  3921.                     
  3922.                     tre = srcDataPtr[0] - srcDataPtr[len];
  3923.                     tim = srcDataPtr[1] - srcDataPtr[len + 1];
  3924.                     dstDataPtr[0] = srcDataPtr[0] + srcDataPtr[len];
  3925.                     dstDataPtr[1] = srcDataPtr[1] + srcDataPtr[len+1];
  3926.                     dstDataPtr[2*trig] = c*tre - s*tim;
  3927.                     dstDataPtr[2*trig + 1] = s*tre + c*tim;
  3928.                     srcDataPtr += 2; dstDataPtr += 2;
  3929.  
  3930.                 }
  3931.  
  3932.                 ////////////////////////////////////////////////////////////////////////////////
  3933.                 // update dest pointer and root value
  3934.                 ////////////////////////////////////////////////////////////////////////////////
  3935.                 
  3936.                 dstDataPtr += 2*trig;
  3937.                 root += trig;
  3938.  
  3939.             }
  3940.  
  3941.             ////////////////////////////////////////////////////////////////////////////////
  3942.             // update trig value and ping pong source and dest pointers
  3943.             ////////////////////////////////////////////////////////////////////////////////
  3944.  
  3945.             trig *= 2; srcDataPtr -= len; dstDataPtr -= 2*len;
  3946.             tmp = srcDataPtr; srcDataPtr = dstDataPtr; dstDataPtr = tmp; 
  3947.  
  3948.         }
  3949.  
  3950.         ////////////////////////////////////////////////////////////////////////////////
  3951.         // For last iteration, we are fortunate in that the source indices for the
  3952.         // butterfly calculations are the same as the destination indices. This is
  3953.         // not true for other loop iterations, which is why we cannot simply store
  3954.         // our results directly back to the data -- we would overwrite source data
  3955.         // that had not yet been used for the current iteration of the loop. If the
  3956.         // power of two of the length is odd, then, on the second to last iteration,
  3957.         // the data will end up ping-ponged back to the source buffer.  If this is the
  3958.         // case, then we set source and dest to be the same. Otherwise, if the power
  3959.         // of two is even, then we will be reading from temp data, and writing back
  3960.         // to our original buffer.
  3961.         ////////////////////////////////////////////////////////////////////////////////
  3962.  
  3963.         if (pow & 1) {
  3964.             dstDataPtr = srcDataPtr;
  3965.         }
  3966.     
  3967.         root = 0;
  3968.         
  3969.         if (isign > 0) {
  3970.         
  3971.             ////////////////////////////////////////////////////////////////////////////////
  3972.             // we are performing an inverse FFT.  We need to divide all elements of the
  3973.             // final result by len.  Since the float multiply operation is faster than
  3974.             // the divide operation, we multiply by the reciprocal.
  3975.             ////////////////////////////////////////////////////////////////////////////////
  3976.             inverseDivideMultiplier = (double)1/len;
  3977.             
  3978.             while(root < len/2) {
  3979.  
  3980.                 ////////////////////////////////////////////////////////////////////////////////
  3981.                 // load cos and sin values for current root value.
  3982.                 ////////////////////////////////////////////////////////////////////////////////
  3983.  
  3984.                 c = sinCosTable[2*root];
  3985.                 s = isign*sinCosTable[2*root+1];
  3986.  
  3987.                 for(j = trig; j > 0; j--) {
  3988.  
  3989.                     ////////////////////////////////////////////////////////////////////////////////
  3990.                     // calculate butterflies.  For inputs:
  3991.                     // [re0, im0] [re1, im1]
  3992.                     //
  3993.                     // we calculate:
  3994.                     //
  3995.                     // out0 = [re0+re1, im0+im1]
  3996.                     //
  3997.                     // out1 = [ cos * (re0-re1) - sin * (im0-im1),
  3998.                     //            sin * (re0-re1) + cos * (im0-im1) ]
  3999.                     //
  4000.                     //
  4001.                     // We also divide each element by the length of the signal (this is done
  4002.                     // by multiplying by the reciprocal).
  4003.                     ////////////////////////////////////////////////////////////////////////////////
  4004.                     
  4005.                     tre = srcDataPtr[0] - srcDataPtr[len];
  4006.                     tim = srcDataPtr[1] - srcDataPtr[len + 1];
  4007.                     dstDataPtr[0] = (srcDataPtr[0] + srcDataPtr[len])*inverseDivideMultiplier;
  4008.                     dstDataPtr[1] = (srcDataPtr[1] + srcDataPtr[len+1])*inverseDivideMultiplier;
  4009.                     dstDataPtr[2*trig] = (c*tre - s*tim)*inverseDivideMultiplier;
  4010.                     dstDataPtr[2*trig + 1] = (s*tre + c*tim)*inverseDivideMultiplier;
  4011.                     srcDataPtr += 2; dstDataPtr += 2;
  4012.  
  4013.                 }
  4014.  
  4015.                 ////////////////////////////////////////////////////////////////////////////////
  4016.                 // update dest pointer and root value
  4017.                 ////////////////////////////////////////////////////////////////////////////////
  4018.                 
  4019.                 dstDataPtr += 2*trig;
  4020.                 root += trig;
  4021.  
  4022.             }
  4023.         } else {
  4024.         
  4025.             while(root < len/2) {
  4026.  
  4027.                 ////////////////////////////////////////////////////////////////////////////////
  4028.                 // load cos and sin values for current root value.
  4029.                 ////////////////////////////////////////////////////////////////////////////////
  4030.  
  4031.                 c = sinCosTable[2*root];
  4032.                 s = isign*sinCosTable[2*root+1];
  4033.  
  4034.                 for(j = trig; j > 0; j--) {
  4035.  
  4036.                     ////////////////////////////////////////////////////////////////////////////////
  4037.                     // calculate butterflies.  For inputs:
  4038.                     // [re0, im0] [re1, im1]
  4039.                     //
  4040.                     // we calculate:
  4041.                     //
  4042.                     // out0 = [re0+re1, im0+im1]
  4043.                     //
  4044.                     // out1 = [ cos * (re0-re1) - sin * (im0-im1),
  4045.                     //            sin * (re0-re1) + cos * (im0-im1) ]
  4046.                     //
  4047.                     ////////////////////////////////////////////////////////////////////////////////
  4048.                     
  4049.                     tre = srcDataPtr[0] - srcDataPtr[len];
  4050.                     tim = srcDataPtr[1] - srcDataPtr[len + 1];
  4051.                     dstDataPtr[0] = srcDataPtr[0] + srcDataPtr[len];
  4052.                     dstDataPtr[1] = srcDataPtr[1] + srcDataPtr[len+1];
  4053.                     dstDataPtr[2*trig] = c*tre - s*tim;
  4054.                     dstDataPtr[2*trig + 1] = s*tre + c*tim;
  4055.                     srcDataPtr += 2; dstDataPtr += 2;
  4056.  
  4057.                 }
  4058.  
  4059.                 ////////////////////////////////////////////////////////////////////////////////
  4060.                 // update dest pointer and root value
  4061.                 ////////////////////////////////////////////////////////////////////////////////
  4062.                 
  4063.                 dstDataPtr += 2*trig;
  4064.                 root += trig;
  4065.  
  4066.             }
  4067.         }
  4068.  
  4069.     }
  4070.  
  4071.     return result;    
  4072.  
  4073. }
  4074.  
  4075. ////////////////////////////////////////////////////////////////////////////////
  4076. //
  4077. //    fft_pingpong
  4078. //
  4079. // This function calls either the scalar or vector implementation of the
  4080. // pingpong fft, based on the length of the data.  The vector implementation
  4081. // only works above certain lengths because of implementation details.
  4082. ////////////////////////////////////////////////////////////////////////////////
  4083. static OSErr fft_pingpong(float *data, unsigned long len, long isign)
  4084. {
  4085.     OSErr        result = noErr;
  4086.  
  4087.     ////////////////////////////////////////////////////////////////////////////////
  4088.     // make sure that our temp buffer is sufficiently large to hold a copy of
  4089.     // the data.
  4090.     ////////////////////////////////////////////////////////////////////////////////
  4091.     result = EnsureStaticBufferSize(len);
  4092.     
  4093.     if (result == noErr) {
  4094.  
  4095.         if (len < ALTIVEC_COMPLEX_MIN_LENGTH) {
  4096.  
  4097.             ////////////////////////////////////////////////////////////////////////////////
  4098.             // call scalar version
  4099.             ////////////////////////////////////////////////////////////////////////////////        
  4100.             result = fft_scalar(data, *(float**)gTempBufferHandle, len, isign);
  4101.             
  4102.         } else {
  4103.         
  4104.             ////////////////////////////////////////////////////////////////////////////////
  4105.             // call AltiVec version
  4106.             ////////////////////////////////////////////////////////////////////////////////
  4107.             result = fft_altivec(data, *(float**)gTempBufferHandle, len, isign);
  4108.             
  4109.         }
  4110.  
  4111.     }    
  4112.     
  4113.     return result;
  4114. }
  4115.  
  4116.  
  4117. ////////////////////////////////////////////////////////////////////////////////
  4118. //    FFTComplex
  4119. //
  4120. //    Performs a forward or inverse complex FFT on the data.  This is a wrapper
  4121. // function for three different FFT routines.  If the length is below the
  4122. // breakover to call the recursive FFT, then it calls the pingpong FFT.  If
  4123. // it's above the point at which the recursive FFT is faster, then it calls
  4124. // one of the recursive FFTs.  If this is the case, then it chooses between
  4125. // two forms of recursion.  For even powers of two, it calls the matrix
  4126. // FFT (which can only be performed on even powers of two because it allows
  4127. // for a square matrix, which can be easily transposed).  If the length is
  4128. // an odd power of two, then a one-step recursive FFT is called.
  4129. ////////////////////////////////////////////////////////////////////////////////
  4130. OSErr FFTComplex(float *data, long length, long isign)
  4131. {
  4132.     OSErr            result = noErr;
  4133.     
  4134.     if (length <= PINGPONG_FFT_MAXLEN) {
  4135.         
  4136.         ////////////////////////////////////////////////////////////////////////////////
  4137.         // length is in the range where pingpong FFT is fastest
  4138.         ////////////////////////////////////////////////////////////////////////////////
  4139.         result = fft_pingpong(data, length, isign);    
  4140.         
  4141.     } else {
  4142.     
  4143.         long pow = log2max(length);
  4144.         
  4145.         if (!(pow & 1)) {
  4146.         
  4147.             ////////////////////////////////////////////////////////////////////////////////
  4148.             // data can be represented in a square matrix, so call matrix FFT
  4149.             ////////////////////////////////////////////////////////////////////////////////
  4150.             result = fft_square_matrix(data, length, isign);
  4151.             
  4152.         } else {
  4153.         
  4154.             ////////////////////////////////////////////////////////////////////////////////
  4155.             // data length is odd power of two, so call recursive FFT
  4156.             ////////////////////////////////////////////////////////////////////////////////
  4157.             result = fft_recursive(data, length, isign);
  4158.             
  4159.         }
  4160.     }
  4161.     
  4162.     return result;
  4163. }
  4164.  
  4165.  
  4166. #pragma mark -
  4167. #pragma mark R E A L   F F T
  4168.  
  4169.  
  4170.  
  4171. ////////////////////////////////////////////////////////////////////////////////
  4172. //    fft_real_forward_altivec
  4173. //
  4174. //    Given a real signal X = x_0 ... x_(n-1), one can calculate a real-signal
  4175. //    fft as follows:
  4176. //    
  4177. //    First, the real signal is treated as complex data (of length n/2), and
  4178. //    a complex FFT is performed on X to yield complex data U, with 
  4179. //    U = u_0...u_(n/2-1).
  4180. //    
  4181. //    Next, the signal U is used to define e_k and o_k (k in [0, n/2],
  4182. //    with e_n/2 = e_0), where
  4183. //    
  4184. //    e_k = (u_k + u_(n/2 - k)*) / 2
  4185. //
  4186. //    o_k = (u_k + u_(n/2 - k)*) / 2i
  4187. //    
  4188. //    Given e_k and o_k, we define Y as
  4189. //    
  4190. //    Y_k = e_k + ( e^(-2*pi*i*k/N) * o_k ) 
  4191. //    
  4192. //    for k in [0, n/2].  Then, the signal Y is the real-signal FFT.
  4193. //
  4194. //    Result is stored in hermitian order, so that it may occupy the exact same
  4195. //  space as the original data.  Given the complex-signal FFT result Y,
  4196. //    this result is stored in the order:
  4197. //
  4198. //    Y(0)r Y(N/2)r Y(1)r Y(1)i Y(2)r Y(2)i ... Y(N/2-1)r    Y(N/2-1)i
  4199. ////////////////////////////////////////////////////////////////////////////////
  4200. static OSErr fft_real_forward_altivec(float *data, long length)
  4201. {
  4202.     OSErr                        result = noErr;
  4203.     vector float                *pInVecLo, *pInVecHi;
  4204.     vector float                *pOutVecLo, *pOutVecHi;
  4205.     vector float                vInLoNext, vInHiPrev;
  4206.     
  4207.     vector float                vUHi1, vUHi2, vULo1, vULo2;
  4208.     vector float                vZero;
  4209.     vector float                vDiffLo, vDiffHi;
  4210.     vector float                vSumLo, vSumHi;
  4211.     
  4212.     vector unsigned long        vHiLoSelect;
  4213.     vector unsigned long        vAlternateSelect;
  4214.  
  4215.     vector unsigned char        vNewSinLoPerm;
  4216.     vector unsigned char        vNewCosLoPerm;
  4217.     
  4218.     vector unsigned char        vAdderPerm;
  4219.     vector unsigned char        vFirstMulPerm;
  4220.     vector unsigned char        vSecondMulPerm;
  4221.  
  4222.     vector float                vFirstMul;
  4223.     vector float                vSecondMul;
  4224.  
  4225.     vector float                vSinLo;
  4226.     vector float                vCosLo;
  4227.  
  4228.     vector float                vResultLo, vResultHi;
  4229.  
  4230.     vector float                vSinHi;
  4231.     vector float                vCosHi;
  4232.  
  4233.     vector float                vOneHalf;
  4234.  
  4235.     vector float                vAlternateNegate;
  4236.     vector float                vAlternateNegate2;
  4237.     
  4238.     long                        i;
  4239.  
  4240.     vector float                vFTransition;
  4241.  
  4242.  
  4243.     double                        updateA;
  4244.     double                        updateB;
  4245.  
  4246.     double                        newCos1;
  4247.     double                        newCos2;
  4248.     double                        newSin1;
  4249.     double                        newSin2;
  4250.  
  4251.     double                        tempCos1;
  4252.     double                        tempCos2;
  4253.  
  4254.     float                        real0;
  4255.     float                        im0;
  4256.  
  4257.     
  4258.     ////////////////////////////////////////////////////////////////////////////////
  4259.     // perform a forward complex fft on our real signal data, treating it as a
  4260.     // half-length complex signal.
  4261.     ////////////////////////////////////////////////////////////////////////////////
  4262.     
  4263.     result = FFTComplex(data, length/2, -1);
  4264.  
  4265.     if (result == noErr) {
  4266.  
  4267.         ////////////////////////////////////////////////////////////////////////////////
  4268.         // initialize zero vector
  4269.         ////////////////////////////////////////////////////////////////////////////////
  4270.         vZero = (vector float)(0);
  4271.  
  4272.         ////////////////////////////////////////////////////////////////////////////////
  4273.         // create a select vector that will select the first two elements of vector
  4274.         // one, and second two elements of vector two
  4275.         ////////////////////////////////////////////////////////////////////////////////
  4276.         vHiLoSelect = (vector unsigned long)((vector signed long)(-1, -1, 0, 0));
  4277.  
  4278.         ////////////////////////////////////////////////////////////////////////////////
  4279.         // create a select vector that will select alternate elements from first and
  4280.         // second input vectors
  4281.         ////////////////////////////////////////////////////////////////////////////////
  4282.         vAlternateSelect = (vector unsigned long)((vector signed long)(0, -1, 0, -1));
  4283.  
  4284.         ////////////////////////////////////////////////////////////////////////////////
  4285.         // create a permute vector that, given input vectors 
  4286.         //
  4287.         // X = x0 x1 x2 x3
  4288.         // Y = y0 y1 y2 y3
  4289.         //
  4290.         // will create the output vector
  4291.         // Z = x0 x0 y3 y3
  4292.         ////////////////////////////////////////////////////////////////////////////////
  4293.         vNewSinLoPerm = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 28, 29, 30, 31, 28, 29, 30, 31);
  4294.  
  4295.         ////////////////////////////////////////////////////////////////////////////////
  4296.         // create a permute vector that, given input vectors 
  4297.         //
  4298.         // X = x0 x1 x2 x3
  4299.         // Y = y0 y1 y2 y3
  4300.         //
  4301.         // will create the output vector
  4302.         // Z = x0 x0 y1 y1
  4303.         ////////////////////////////////////////////////////////////////////////////////
  4304.         vNewCosLoPerm = (vector unsigned char)(4, 5, 6, 7, 4, 5, 6, 7, 20, 21, 22, 23, 20, 21, 22, 23);
  4305.         
  4306.         ////////////////////////////////////////////////////////////////////////////////
  4307.         // create a permute vector that, given input vectors 
  4308.         //
  4309.         // X = x0 x1 x2 x3
  4310.         // Y = y0 y1 y2 y3
  4311.         //
  4312.         // will create the output vector
  4313.         // Z = x0 y1 x2 y3
  4314.         ////////////////////////////////////////////////////////////////////////////////
  4315.         vAdderPerm = (vector unsigned char)(0, 1, 2, 3,    20, 21, 22, 23, 8, 9, 10, 11, 28, 29, 30, 31);
  4316.         
  4317.         ////////////////////////////////////////////////////////////////////////////////
  4318.         // create a permute vector that, given input vectors 
  4319.         //
  4320.         // X = x0 x1 x2 x3
  4321.         // Y = y0 y1 y2 y3
  4322.         //
  4323.         // will create the output vector
  4324.         // Z = x1 y0 x3 y2
  4325.         ////////////////////////////////////////////////////////////////////////////////
  4326.         vFirstMulPerm = (vector unsigned char)(4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15, 24, 25, 26, 27);
  4327.  
  4328.         ////////////////////////////////////////////////////////////////////////////////
  4329.         // create a permute vector that, given input vectors 
  4330.         //
  4331.         // X = x0 x1 x2 x3
  4332.         // Y = y0 y1 y2 y3
  4333.         //
  4334.         // will create the output vector
  4335.         // Z = y0 x1 y2 x3
  4336.         ////////////////////////////////////////////////////////////////////////////////
  4337.         vSecondMulPerm = (vector unsigned char)(16, 17, 18, 19, 4, 5, 6, 7, 24, 25, 26, 27, 12, 13, 14, 15);
  4338.  
  4339.         ////////////////////////////////////////////////////////////////////////////////
  4340.         // create float vector of 0.5
  4341.         ////////////////////////////////////////////////////////////////////////////////
  4342.         vOneHalf = (vector float)(0.5);
  4343.  
  4344.         ////////////////////////////////////////////////////////////////////////////////
  4345.         // create a multiply vector that will negate second and fourth elements
  4346.         ////////////////////////////////////////////////////////////////////////////////
  4347.         vAlternateNegate = (vector float)(1, -1, 1, -1);
  4348.  
  4349.         ////////////////////////////////////////////////////////////////////////////////
  4350.         // create a multiply vector that will negate first and third elements
  4351.         ////////////////////////////////////////////////////////////////////////////////
  4352.         vAlternateNegate2 = (vector float)(-1, 1, -1, 1);
  4353.  
  4354.         ////////////////////////////////////////////////////////////////////////////////
  4355.         //
  4356.         //    Given c = cos(w) and s = sin(w), if we
  4357.         //    want to find the cos and sin of w plus
  4358.         //    some small angle d, then we can do so
  4359.         //    by defining:
  4360.         //    
  4361.         //    a = 2 * ((sin(d/2)) ^ 2)
  4362.         //    b = sin(d)
  4363.         //    
  4364.         //    Then, we can calculate the cos and sin
  4365.         //    of the updated angle w+d as:
  4366.         //    
  4367.         //    cos(w+d) = c - ac - bs
  4368.         //    sin(w+d) = s - as + bc
  4369.         //    
  4370.         //    We will need to incrementally calculate
  4371.         //    cos(w) and sin(w), so we define the
  4372.         //    following scalar values.  We use scalar
  4373.         //    because we need the precision of doubles,
  4374.         //    and vectors are floats.    
  4375.         //
  4376.         ////////////////////////////////////////////////////////////////////////////////
  4377.  
  4378.         updateA = sin(2*PI/length);
  4379.         updateA *= updateA*2;
  4380.  
  4381.         updateB = sin(4*PI/length);
  4382.         
  4383.         ////////////////////////////////////////////////////////////////////////////////
  4384.         //
  4385.         // We want to have four cos and sin vectors that are updated incrementally, using
  4386.         // the doubles that we have used to calculate our new values.  To do this we
  4387.         // have a "transition" vector that allows us to get our scalar values into the
  4388.         // vector domain.
  4389.         //
  4390.         // Scalar values are stored into the elements of the transition vector, and then
  4391.         // our end cos and sin vectors are created by permuting values out of our
  4392.         // transition vector and other previously created sin and cos vectors.
  4393.         // 
  4394.         // We also take advantage of the fact that
  4395.         // sin(pi - d) = sin(0 + d) 
  4396.         // and
  4397.         // cos(pi - d) = -cos(0 + d) 
  4398.         // 
  4399.         ////////////////////////////////////////////////////////////////////////////////
  4400.  
  4401.         ////////////////////////////////////////////////////////////////////////////////
  4402.         // We store values into vFTransiton so that we can create:
  4403.         // 
  4404.         // vCosLo = cos(0) cos(0) cos(2pi/length) cos(2pi/length)    
  4405.         //
  4406.         ////////////////////////////////////////////////////////////////////////////////
  4407.         
  4408.         ((float*)&vFTransition)[0] = 1;
  4409.         ((float*)&vFTransition)[1] = 1;
  4410.  
  4411.         newCos1 = cos(2*PI/length);
  4412.         ((float*)&vFTransition)[2] = newCos1;
  4413.         ((float*)&vFTransition)[3] = newCos1;
  4414.  
  4415.         vCosLo = vFTransition;
  4416.  
  4417.         ////////////////////////////////////////////////////////////////////////////////
  4418.         // We store values into vFTransiton so that we can create:
  4419.         // 
  4420.         // vCosHi = cos(2*2pi/length) cos(2*2pi/length) cos(2pi/length) cos(2pi/length)    
  4421.         //
  4422.         ////////////////////////////////////////////////////////////////////////////////
  4423.  
  4424.         newCos2 = cos(4*PI/length);
  4425.         ((float*)&vFTransition)[0] = newCos2;
  4426.         ((float*)&vFTransition)[1] = newCos2;
  4427.         
  4428.         vCosHi = vFTransition;
  4429.         
  4430.         ////////////////////////////////////////////////////////////////////////////////
  4431.         // We store values into vFTransiton so that we can create:
  4432.         // 
  4433.         // vSinLo = sin(0) sin(0) sin(2pi/length) sin(2pi/length)    
  4434.         //
  4435.         ////////////////////////////////////////////////////////////////////////////////
  4436.         ((float*)&vFTransition)[0] = 0;
  4437.         ((float*)&vFTransition)[1] = 0;
  4438.         
  4439.         newSin1 = sin(2*PI/length);
  4440.         ((float*)&vFTransition)[2] = newSin1;
  4441.         ((float*)&vFTransition)[3] = newSin1;
  4442.  
  4443.         vSinLo = vFTransition;
  4444.                 
  4445.         ////////////////////////////////////////////////////////////////////////////////
  4446.         // We store values into vFTransiton so that we can create:
  4447.         // 
  4448.         // vSinHi = sin(2*2pi/length) sin(2*2pi/length) sin(2pi/length) sin(2pi/length)    
  4449.         //
  4450.         ////////////////////////////////////////////////////////////////////////////////
  4451.         newSin2 = sin(4*PI/length);
  4452.         ((float*)&vFTransition)[0] = newSin2;
  4453.         ((float*)&vFTransition)[1] = newSin2;
  4454.  
  4455.         vSinHi = vFTransition;
  4456.  
  4457.         ////////////////////////////////////////////////////////////////////////////////
  4458.         // save real[0] and im[0] for later use
  4459.         ////////////////////////////////////////////////////////////////////////////////
  4460.                         
  4461.         real0 = data[0];
  4462.         im0 = data[1];
  4463.  
  4464.         ////////////////////////////////////////////////////////////////////////////////
  4465.         // set up hi,lo pointers for input from data to point at first and last vectors,
  4466.         // and do the same for output vectors, since we overwrite our results in place.
  4467.         ////////////////////////////////////////////////////////////////////////////////
  4468.         pInVecLo = (vector float*)data;
  4469.         pInVecHi = pInVecLo + (length/4) - 1;
  4470.  
  4471.         pOutVecLo = pInVecLo;
  4472.         pOutVecHi = pInVecHi;
  4473.  
  4474.         ////////////////////////////////////////////////////////////////////////////////
  4475.         // get 0 element for wraparound, since U_{n/2} = U_0.
  4476.         ////////////////////////////////////////////////////////////////////////////////
  4477.         vInLoNext = *pInVecLo++;
  4478.         vInHiPrev = vInLoNext;
  4479.         
  4480.         ////////////////////////////////////////////////////////////////////////////////
  4481.         // Loop through all elements.  Since each vector is four elements, and we are
  4482.         // calculating two vectors per iteration through the loop, we calculate 8 
  4483.         // elements per loop, and so we iterate through the loop (length/8) times.
  4484.         ////////////////////////////////////////////////////////////////////////////////
  4485.  
  4486.         for (i = 0; i<length/8; i++) {
  4487.             
  4488.             ////////////////////////////////////////////////////////////////////////////////
  4489.             // negate alternating elements of vCosLo and vCosHi vectors.
  4490.             ////////////////////////////////////////////////////////////////////////////////
  4491.             vCosLo = vec_madd(vCosLo, vAlternateNegate, vZero);
  4492.             vCosHi = vec_madd(vCosHi, vAlternateNegate2, vZero);
  4493.          
  4494.             ////////////////////////////////////////////////////////////////////////////////
  4495.             // calculate new sin, cos for next time through loop, using our incremental
  4496.             // updating algorithm
  4497.             ////////////////////////////////////////////////////////////////////////////////
  4498.             tempCos1     = newCos1 - (updateA*newCos1  + updateB * newSin1);
  4499.             newSin1     = newSin1 - (updateA*newSin1  - updateB * newCos1);
  4500.             newCos1     = tempCos1;
  4501.  
  4502.             tempCos2     = newCos2 - (updateA*newCos2  + updateB * newSin2);
  4503.             newSin2     = newSin2 - (updateA*newSin2  - updateB * newCos2);
  4504.             newCos2     = tempCos2;
  4505.             
  4506.             ////////////////////////////////////////////////////////////////////////////////
  4507.             // Using vectors we load in, and vectors from previous time through loop, we
  4508.             // generate the vectors:
  4509.             //
  4510.             // vULo1 =     re[k]         im[k]         re[k+1]        im[k+1]
  4511.             // vULo2 =    re[n/2-k]    im[n/2-k]    re[n/2-k-1]    im[n/2-k-1]
  4512.             //
  4513.             // vUHi1 =     re[n/2-k-1]    im[n/2-k-1]    re[n/2-k-2]    im[n/2-k-2]
  4514.             // vUHi2 =    re[k+1]     im[k+1]     re[k+2]        im[k+2]
  4515.             //
  4516.             // with k = 2*i (where i is the loop iterator)
  4517.             ////////////////////////////////////////////////////////////////////////////////
  4518.                     
  4519.             vULo1 = vInLoNext;
  4520.             vUHi1 = *pInVecHi--;
  4521.                     
  4522.             vULo2 = vec_sel(vUHi1, vInHiPrev, vHiLoSelect);
  4523.             
  4524.             vInHiPrev = vUHi1;
  4525.             
  4526.             vInLoNext = *pInVecLo++;
  4527.             
  4528.             vUHi2 = vec_sel(vULo1, vInLoNext, vHiLoSelect);
  4529.  
  4530.             ////////////////////////////////////////////////////////////////////////////////
  4531.             //    Calculate sum and difference of vULo1 and vULo2, which are:
  4532.             //
  4533.             // vSumLo = re[k]+re[n/2-k], im[k]+im[n/2-k], re[k+1]+re[n/2-k-1], im[k+1]+im[n/2-k-1]
  4534.             // vDiffLo = re[k]-re[n/2-k], im[k]-im[n/2-k], re[k+1]-re[n/2-k-1], im[k+1]-im[n/2-k-1]
  4535.             ////////////////////////////////////////////////////////////////////////////////
  4536.  
  4537.             vSumLo = vec_add(vULo1, vULo2);        
  4538.             vDiffLo = vec_sub(vULo1, vULo2);        
  4539.  
  4540.             ////////////////////////////////////////////////////////////////////////////////
  4541.             //    We start by generating a result vector that is:
  4542.             //
  4543.             // vResultLo = re[k]+re[n/2-k]   im[k]-im[n/2-k]   re[k+1]+re[n/2-k-1]   im[k+1]-im[n/2-k-1]
  4544.             ////////////////////////////////////////////////////////////////////////////////
  4545.             
  4546.             vResultLo = vec_perm(vSumLo, vDiffLo, vAdderPerm);
  4547.  
  4548.             ////////////////////////////////////////////////////////////////////////////////
  4549.             // Next we create a multiplier vector that is:
  4550.             //
  4551.             // vFirstMul = im[k]+im[n/2-k]   re[k]-re[n/2-k]    im[k+1]+im[n/2-k-1]   re[k+1]-re[n/2-k-1]
  4552.             ////////////////////////////////////////////////////////////////////////////////
  4553.  
  4554.             vFirstMul = vec_perm(vSumLo, vDiffLo, vFirstMulPerm);            
  4555.  
  4556.             ////////////////////////////////////////////////////////////////////////////////
  4557.             // Next we create a multiplier vector that is:
  4558.             //
  4559.             // vSecondMul = re[k]-re[n/2-k]   im[k]+im[n/2-k]   re[k+1]-re[n/2-k-1]   im[k+1]+im[n/2-k-1]
  4560.             ////////////////////////////////////////////////////////////////////////////////
  4561.  
  4562.             vSecondMul = vec_perm(vSumLo, vDiffLo, vSecondMulPerm);        
  4563.         
  4564.             ////////////////////////////////////////////////////////////////////////////////
  4565.             // We now calculate:
  4566.             //
  4567.             // vResultLo = 
  4568.             //
  4569.             //        re[k]+re[n/2-k] + (im[k]+im[n/2-k]) * cos(k*2pi/length),
  4570.             //        im[k]-im[n/2-k] + (re[k]-re[n/2-k]) * -cos(k*2pi/length),
  4571.             //        re[k+1]+re[n/2-k-1] + (im[k+1]+im[n/2-k-1]) * cos((k+1)*2pi/length),
  4572.             //        im[k+1]-im[n/2-k-1] + (re[k+1]-re[n/2-k-1]) * -cos((k+1)*2pi/length)
  4573.             //        
  4574.             ////////////////////////////////////////////////////////////////////////////////
  4575.  
  4576.             vResultLo = vec_madd(vCosLo, vFirstMul, vResultLo);
  4577.  
  4578.             ////////////////////////////////////////////////////////////////////////////////
  4579.             // with a negative multiply-subtract, we calculate
  4580.             //
  4581.             // vResultLo = 
  4582.             //
  4583.             //        re[k]+re[n/2-k]     + (im[k]+im[n/2-k]) * cos(k*2pi/length)                + (re[k]-re[n/2-k]) * -sin(k*2pi/length),
  4584.             //        im[k]-im[n/2-k]     + (re[k]-re[n/2-k]) * -cos(k*2pi/length)            + (im[k]+im[n/2-k]) * -sin(k*2pi/length),
  4585.             //        re[k+1]+re[n/2-k-1] + (im[k+1]+im[n/2-k-1]) * cos((k+1)*2pi/length)        + (re[k+1]-re[n/2-k-1]) * -sin((k+1)*2pi/length),
  4586.             //        im[k+1]-im[n/2-k-1] + (re[k+1]-re[n/2-k-1]) * -cos((k+1)*2pi/length)    + (im[k+1]+im[n/2-k-1]) * -sin((k+1)*2pi/length)
  4587.             //        
  4588.             ////////////////////////////////////////////////////////////////////////////////
  4589.  
  4590.             vResultLo = vec_nmsub(vSinLo, vSecondMul, vResultLo);
  4591.             
  4592.             ////////////////////////////////////////////////////////////////////////////////
  4593.             // finally, divide all elements by two (multiply by one half).  With this
  4594.             // step finished, we have calculated 
  4595.             // e_k + (e^(-2pi*i*k/N) * o_k), e_(k+1) + (e^(-2pi*i*(k+1)/N) * o_(k+1))
  4596.             ////////////////////////////////////////////////////////////////////////////////
  4597.  
  4598.             vResultLo = vec_madd(vResultLo, vOneHalf, vZero);
  4599.             
  4600.             ////////////////////////////////////////////////////////////////////////////////
  4601.             // store this vector back, overwriting source data. 
  4602.             ////////////////////////////////////////////////////////////////////////////////
  4603.  
  4604.             *pOutVecLo++ = vResultLo;
  4605.             
  4606.             ////////////////////////////////////////////////////////////////////////////////
  4607.             // store our new angles to the transition vector, and generate new cos,sin
  4608.             // vectors from them.
  4609.             ////////////////////////////////////////////////////////////////////////////////
  4610.             
  4611.             ((float*)&vFTransition)[0] = newCos2;
  4612.             ((float*)&vFTransition)[1] = newCos1;
  4613.             ((float*)&vFTransition)[2] = newSin2;
  4614.             ((float*)&vFTransition)[3] = newSin1;
  4615.  
  4616.             vCosLo = vec_perm(vCosHi, vFTransition, vNewCosLoPerm);
  4617.                     
  4618.             vSinLo = vec_perm(vSinHi, vFTransition, vNewSinLoPerm);
  4619.                     
  4620.             ////////////////////////////////////////////////////////////////////////////////
  4621.             // Calculate 
  4622.             // e_k + (e^(-2pi*i*k/N) * o_k), e_(k+1) + (e^(-2pi*i*(k+1)/N) * o_(k+1))
  4623.             // for high elements in array
  4624.             ////////////////////////////////////////////////////////////////////////////////
  4625.  
  4626.             vSumHi = vec_add(vUHi1, vUHi2);        
  4627.             vDiffHi = vec_sub(vUHi1, vUHi2);        
  4628.                             
  4629.             vFirstMul = vec_perm(vSumHi, vDiffHi, vFirstMulPerm);
  4630.             vSecondMul = vec_perm(vSumHi, vDiffHi, vSecondMulPerm);
  4631.             
  4632.             vResultHi = vec_perm(vSumHi, vDiffHi, vAdderPerm);
  4633.  
  4634.             vResultHi = vec_madd(vCosHi, vFirstMul, vResultHi);
  4635.             vResultHi = vec_nmsub(vSinHi, vSecondMul, vResultHi);
  4636.             
  4637.             vResultHi = vec_madd(vResultHi, vOneHalf, vZero);
  4638.  
  4639.             ////////////////////////////////////////////////////////////////////////////////
  4640.             // create new angle vectors from our transition vectors for next time
  4641.             // through loop
  4642.             ////////////////////////////////////////////////////////////////////////////////
  4643.             vCosHi = vec_mergeh(vFTransition, vFTransition);        
  4644.             vSinHi = vec_mergel(vFTransition, vFTransition);
  4645.             
  4646.             ////////////////////////////////////////////////////////////////////////////////
  4647.             // store high result, overwriting source
  4648.             ////////////////////////////////////////////////////////////////////////////////
  4649.             *pOutVecHi-- = vResultHi;
  4650.                             
  4651.         }
  4652.  
  4653.         ////////////////////////////////////////////////////////////////////////////////
  4654.         // finally, store re[n/2]
  4655.         ////////////////////////////////////////////////////////////////////////////////
  4656.         data[1] = real0-im0;
  4657.  
  4658.     }
  4659.     
  4660.     return result;
  4661. }
  4662.  
  4663. ////////////////////////////////////////////////////////////////////////////////
  4664. //    fft_real_forward_altivec
  4665. //
  4666. //    Given Y, a complex-result FFT of a real signal, the inverse real FFT can
  4667. // be taken with the following steps:
  4668. //
  4669. //    First, define the signals e_k and o_k:
  4670. //
  4671. //    e_k = 1/2 * (Y_k + (Y_N/2-k)*)
  4672. //
  4673. //    o_k = 1/2 * (Y_k - (Y_N/2-k)*) * e_^(2pi i k / N)
  4674. //
  4675. //    where N is the (real) signal length, and Y* is Y conjugate, for k=(0, N/2)
  4676. //
  4677. //    Next, from this, generate a signal X:
  4678. //
  4679. //    X_k = e_k + i*o_k         (k = (0, N/2)
  4680. //
  4681. // Then, perform the inverse complex FFT in this length-N/2 signal.  The result
  4682. // is the real, in-order inverse FFT.
  4683. //
  4684. ////////////////////////////////////////////////////////////////////////////////
  4685. static OSErr fft_real_inverse_altivec(float *data, long length)
  4686. {
  4687.     OSErr                        result = noErr;
  4688.     vector float                *pInVecLo;
  4689.     vector float                *pInVecHi;
  4690.     
  4691.     vector float                *pOutVecLo, *pOutVecHi;
  4692.     
  4693.     vector float                vInLoNext, vInHiPrev;
  4694.     
  4695.     vector float                vUHi1, vUHi2, vULo1, vULo2;
  4696.     vector float                vZero;
  4697.     vector float                vDiffLo, vDiffHi;
  4698.     vector float                vSumLo, vSumHi;
  4699.     
  4700.     vector unsigned long        vHiLoSelect;
  4701.  
  4702.     vector unsigned char        vNewSinLoPerm;
  4703.     vector unsigned char        vNewCosLoPerm;
  4704.  
  4705.     vector unsigned char        vAdderPerm;
  4706.     vector unsigned char        vFirstMulPerm;
  4707.     vector unsigned char        vSecondMulPerm;
  4708.  
  4709.     vector float                vFirstMul;
  4710.     vector float                vSecondMul;
  4711.  
  4712.     vector float                vSinLo;
  4713.     vector float                vCosLo;
  4714.  
  4715.     vector float                vResultLo, vResultHi;
  4716.  
  4717.     vector float                vSinHi;
  4718.     vector float                vCosHi;
  4719.  
  4720.     vector float                vOneHalf;
  4721.  
  4722.     vector float                vAlternateNegate;
  4723.     vector float                vAlternateNegate2;
  4724.  
  4725.     vector unsigned long        vClearSecondElementSelect;
  4726.     vector unsigned char         vTwoToOnePermute;
  4727.  
  4728.     long                        i;
  4729.  
  4730.     vector float                vFTransition;
  4731.  
  4732.  
  4733.     double                        updateA;
  4734.     double                        updateB;
  4735.  
  4736.     double                        newCos1;
  4737.     double                        newCos2;
  4738.     double                        newSin1;
  4739.     double                        newSin2;
  4740.  
  4741.     double                        tempCos1;
  4742.     double                        tempCos2;
  4743.  
  4744.  
  4745.     ////////////////////////////////////////////////////////////////////////////////
  4746.     // initialize zero vector
  4747.     ////////////////////////////////////////////////////////////////////////////////
  4748.     vZero = (vector float)(0);
  4749.  
  4750.     ////////////////////////////////////////////////////////////////////////////////
  4751.     // create a select vector that will select the first two elements of vector
  4752.     // one, and second two elements of vector two
  4753.     ////////////////////////////////////////////////////////////////////////////////
  4754.     vHiLoSelect = (vector unsigned long)((vector signed long)(-1, -1, 0, 0));
  4755.  
  4756.     ////////////////////////////////////////////////////////////////////////////////
  4757.     // create a permute vector that, given input vectors 
  4758.     //
  4759.     // X = x0 x1 x2 x3
  4760.     // Y = y0 y1 y2 y3
  4761.     //
  4762.     // will create the output vector
  4763.     // Z = x0 x0 y3 y3
  4764.     ////////////////////////////////////////////////////////////////////////////////
  4765.     vNewSinLoPerm = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 28, 29, 30, 31, 28, 29, 30, 31);
  4766.  
  4767.     ////////////////////////////////////////////////////////////////////////////////
  4768.     // create a permute vector that, given input vectors 
  4769.     //
  4770.     // X = x0 x1 x2 x3
  4771.     // Y = y0 y1 y2 y3
  4772.     //
  4773.     // will create the output vector
  4774.     // Z = x0 x0 y1 y1
  4775.     ////////////////////////////////////////////////////////////////////////////////
  4776.     vNewCosLoPerm = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 20, 21, 22, 23, 20, 21, 22, 23);
  4777.  
  4778.     ////////////////////////////////////////////////////////////////////////////////
  4779.     // create a permute vector that, given input vectors 
  4780.     //
  4781.     // X = x0 x1 x2 x3
  4782.     // Y = y0 y1 y2 y3
  4783.     //
  4784.     // will create the output vector
  4785.     // Z = x0 y1 x2 y3
  4786.     ////////////////////////////////////////////////////////////////////////////////
  4787.     vAdderPerm = (vector unsigned char)(0, 1, 2, 3,    20, 21, 22, 23, 8, 9, 10, 11, 28, 29, 30, 31);
  4788.  
  4789.     ////////////////////////////////////////////////////////////////////////////////
  4790.     // create a permute vector that, given input vectors 
  4791.     //
  4792.     // X = x0 x1 x2 x3
  4793.     // Y = y0 y1 y2 y3
  4794.     //
  4795.     // will create the output vector
  4796.     // Z = x1 y0 x3 y2
  4797.     ////////////////////////////////////////////////////////////////////////////////
  4798.     vFirstMulPerm = (vector unsigned char)(4, 5, 6, 7, 16, 17, 18, 19, 12, 13, 14, 15, 24, 25, 26, 27);
  4799.  
  4800.     ////////////////////////////////////////////////////////////////////////////////
  4801.     // create a permute vector that, given input vectors 
  4802.     //
  4803.     // X = x0 x1 x2 x3
  4804.     // Y = y0 y1 y2 y3
  4805.     //
  4806.     // will create the output vector
  4807.     // Z = y0 x1 y2 x3
  4808.     ////////////////////////////////////////////////////////////////////////////////
  4809.     vSecondMulPerm = (vector unsigned char)(16, 17, 18, 19, 4, 5, 6, 7, 24, 25, 26, 27, 12, 13, 14, 15);
  4810.  
  4811.     ////////////////////////////////////////////////////////////////////////////////
  4812.     // create float vector of 0.5
  4813.     ////////////////////////////////////////////////////////////////////////////////
  4814.     vOneHalf = (vector float)(.5);
  4815.  
  4816.     ////////////////////////////////////////////////////////////////////////////////
  4817.     // create a multiply vector that will negate second and fourth elements
  4818.     ////////////////////////////////////////////////////////////////////////////////
  4819.     vAlternateNegate = (vector float)(1, -1, 1, -1);
  4820.  
  4821.     ////////////////////////////////////////////////////////////////////////////////
  4822.     // create a multiply vector that will negate first and third elements
  4823.     ////////////////////////////////////////////////////////////////////////////////
  4824.     vAlternateNegate2 = (vector float)(-1, 1, -1, 1);
  4825.  
  4826.     ////////////////////////////////////////////////////////////////////////////////
  4827.     // create a select vector that, given the input vectors
  4828.     // 
  4829.     // Y = 0  0  0  0
  4830.     // X = x0 x1 x2 x3
  4831.     //
  4832.     // will create the output vector
  4833.     // x0 0 x2 x3
  4834.     ////////////////////////////////////////////////////////////////////////////////
  4835.     vClearSecondElementSelect = (vector unsigned long)(0xffffffff, 0x00000000, 0xffffffff, 0xffffffff);
  4836.     
  4837.     ////////////////////////////////////////////////////////////////////////////////
  4838.     // create a permute vector that, given the input vectors
  4839.     // 
  4840.     // X = x0 x1 x2 x3
  4841.     // Y = 0  0  0  0
  4842.     //
  4843.     // will create the output vector
  4844.     // x1 0 x2 x3
  4845.     ////////////////////////////////////////////////////////////////////////////////
  4846.     vTwoToOnePermute = (vector unsigned char)(4, 5, 6, 7, 16, 16, 16, 16, 8, 9, 10, 11, 12, 13, 14, 15);
  4847.  
  4848.     ////////////////////////////////////////////////////////////////////////////////
  4849.     //
  4850.     //    Given c = cos(w) and s = sin(w), if we
  4851.     //    want to find the cos and sin of w plus
  4852.     //    some small angle d, then we can do so
  4853.     //    by defining:
  4854.     //    
  4855.     //    a = 2 * ((sin(d/2)) ^ 2)
  4856.     //    b = sin(d)
  4857.     //    
  4858.     //    Then, we can calculate the cos and sin
  4859.     //    of the updated angle w+d as:
  4860.     //    
  4861.     //    cos(w+d) = c - ac - bs
  4862.     //    sin(w+d) = s - as + bc
  4863.     //    
  4864.     //    We will need to incrementally calculate
  4865.     //    cos(w) and sin(w), so we define the
  4866.     //    following scalar values.  We use scalar
  4867.     //    because we need the precision of doubles,
  4868.     //    and vectors are floats.    
  4869.     //
  4870.     ////////////////////////////////////////////////////////////////////////////////
  4871.  
  4872.     updateA = sin(2*PI/length);
  4873.     updateA *= updateA*2;
  4874.  
  4875.     updateB = sin(4*PI/length);
  4876.     
  4877.         ////////////////////////////////////////////////////////////////////////////////
  4878.         //
  4879.         // We want to have four cos and sin vectors that are updated incrementally, using
  4880.         // the doubles that we have used to calculate our new values.  To do this we
  4881.         // have a "transition" vector that allows us to get our scalar values into the
  4882.         // vector domain.
  4883.         //
  4884.         // Scalar values are stored into the elements of the transition vector, and then
  4885.         // our end cos and sin vectors are created by permuting values out of our
  4886.         // transition vector and other previously created sin and cos vectors.
  4887.         // 
  4888.         // We also take advantage of the fact that
  4889.         // sin(pi - d) = sin(0 + d) 
  4890.         // and
  4891.         // cos(pi - d) = -cos(0 + d) 
  4892.         // 
  4893.         ////////////////////////////////////////////////////////////////////////////////
  4894.  
  4895.     ////////////////////////////////////////////////////////////////////////////////
  4896.     // We store values into vFTransiton, creating:
  4897.     // 
  4898.     // vCosLo = cos(0) cos(0) cos(2pi/length) cos(2pi/length)    
  4899.     //
  4900.     ////////////////////////////////////////////////////////////////////////////////
  4901.     
  4902.     ((float*)&vFTransition)[0] = 1;
  4903.     ((float*)&vFTransition)[1] = 1;
  4904.  
  4905.     newCos1 = cos(2*PI/length);
  4906.     ((float*)&vFTransition)[2] = newCos1;
  4907.     ((float*)&vFTransition)[3] = newCos1;
  4908.  
  4909.     vCosLo = vFTransition;
  4910.  
  4911.     ////////////////////////////////////////////////////////////////////////////////
  4912.     // We store values into vFTransiton, creating:
  4913.     // 
  4914.     // vCosHi = -cos(pi-(2*2pi/length)) -cos(pi-(2*2pi/length)) -cos(pi-(2pi/length)) -cos(pi-(2pi/length))    
  4915.     //
  4916.     // We only need to store elements 0 and 1, since elements 2 and 3 already
  4917.     // contain cos(2pi/length), and cos(pi-(2pi/length)) = -cos(2pi/length)
  4918.     ////////////////////////////////////////////////////////////////////////////////
  4919.  
  4920.     newCos2 = cos(4*PI/length);
  4921.     ((float*)&vFTransition)[0] = newCos2;
  4922.     ((float*)&vFTransition)[1] = newCos2;
  4923.     
  4924.     vCosHi = vFTransition;
  4925.     
  4926.     ////////////////////////////////////////////////////////////////////////////////
  4927.     // We store values into vFTransiton, creating:
  4928.     // 
  4929.     // vSinLo = sin(0) sin(0) sin(2pi/length) sin(2pi/length)    
  4930.     //
  4931.     ////////////////////////////////////////////////////////////////////////////////
  4932.  
  4933.     ((float*)&vFTransition)[0] = 0;
  4934.     ((float*)&vFTransition)[1] = 0;
  4935.     
  4936.     newSin1 = sin(2*PI/length);
  4937.     ((float*)&vFTransition)[2] = newSin1;
  4938.     ((float*)&vFTransition)[3] = newSin1;
  4939.  
  4940.     vSinLo = vFTransition;
  4941.             
  4942.     ////////////////////////////////////////////////////////////////////////////////
  4943.     // We store values into vFTransiton, creating:
  4944.     // 
  4945.     // vSinHi = sin(2*2pi/length) sin(2*2pi/length) sin(2pi/length) sin(2pi/length)    
  4946.     //
  4947.     // We only need to store elements 0 and 1, since elements 2 and 3 already
  4948.     // contain sin(2pi/length), and sin(pi-(2pi/length)) = sin(2pi/length)
  4949.     ////////////////////////////////////////////////////////////////////////////////
  4950.  
  4951.     newSin2 = sin(4*PI/length);
  4952.     ((float*)&vFTransition)[0] = newSin2;
  4953.     ((float*)&vFTransition)[1] = newSin2;
  4954.  
  4955.     vSinHi = vFTransition;
  4956.  
  4957.     ////////////////////////////////////////////////////////////////////////////////
  4958.     // set up hi,lo pointers for input from data to point at first and last
  4959.     // vectors, and do the same for output vectors, since we overwrite our
  4960.     // results in place.
  4961.     ////////////////////////////////////////////////////////////////////////////////
  4962.     pInVecLo = (vector float*)data;
  4963.     pInVecHi = pInVecLo + (length/4) - 1;
  4964.  
  4965.     pOutVecLo = pInVecLo;
  4966.     pOutVecHi = pInVecHi;
  4967.  
  4968.     ////////////////////////////////////////////////////////////////////////////////
  4969.     // get 0 element for wraparound, since U_(n/2) = U_0.
  4970.     ////////////////////////////////////////////////////////////////////////////////
  4971.  
  4972.     vInLoNext = *pInVecLo++;
  4973.     
  4974.     ////////////////////////////////////////////////////////////////////////////////
  4975.     // Source data is assumed to be stored in
  4976.     // the order:
  4977.     //
  4978.     // re[0] re[n/2] re[1] im[1] re[2] im[2] re[3]...re[n/2-1] im[n/2-1]
  4979.     // 
  4980.     // Since we want the first high vector to be in the form 
  4981.     // re[n/2-1] im[n/2-1] re[n/2 im[n/2] and we know that im[n/2] = 0,
  4982.     // we want to generate a "previous" high vector in the form
  4983.     //
  4984.     // re[n/2] im[n/2] x x
  4985.     //
  4986.     // so that, in the loop, we can generate the desired output vector of
  4987.     //
  4988.     // re[n/2-1] im[n/2-1] re[n/2 im[n/2] 
  4989.     //
  4990.     // using our "previous" vector and the permute instruction.
  4991.     // So, we create the vector
  4992.     //
  4993.     // vInHiPrev = re[n/2] 0 x x
  4994.     ////////////////////////////////////////////////////////////////////////////////
  4995.  
  4996.     vInHiPrev = vec_perm(vInLoNext, vZero, vTwoToOnePermute);
  4997.  
  4998.     ////////////////////////////////////////////////////////////////////////////////
  4999.     // Since we want the first input vector to be in the form
  5000.     // re[0] im[0] re[1] im[1] 
  5001.     // and we know that im[0] is zero, we simply zero the second element in our
  5002.     // first input vector, which is re[0] re[n/2] re[1] im[1]
  5003.     // to form
  5004.     // vInLoNext = re[0] 0 re[1] im[1]
  5005.     ////////////////////////////////////////////////////////////////////////////////
  5006.  
  5007.     vInLoNext = vec_sel(vZero, vInLoNext, vClearSecondElementSelect);
  5008.     
  5009.     ////////////////////////////////////////////////////////////////////////////////
  5010.     // Loop through all elements.  Since each vector is four elements, and we are
  5011.     // calculating two vectors per iteration through the loop, we calculate 8 elements
  5012.     // per loop, and so we iterate through the loop (length/8) times.
  5013.     ////////////////////////////////////////////////////////////////////////////////
  5014.     for (i = 0; i<length/8; i++) {
  5015.  
  5016.         ////////////////////////////////////////////////////////////////////////////////
  5017.         // negate alternating elements of vCosLo and vCosHi vectors.
  5018.         ////////////////////////////////////////////////////////////////////////////////
  5019.         vCosLo = vec_madd(vCosLo, vAlternateNegate2, vZero);
  5020.         vCosHi = vec_madd(vCosHi, vAlternateNegate, vZero);
  5021.     
  5022.         ////////////////////////////////////////////////////////////////////////////////
  5023.         // calculate new sin, cos for next time through loop, using our incremental
  5024.         // updating algorithm
  5025.         ////////////////////////////////////////////////////////////////////////////////
  5026.         tempCos1     = newCos1 - (updateA*newCos1  + updateB * newSin1);
  5027.         newSin1     = newSin1 - (updateA*newSin1  - updateB * newCos1);
  5028.         newCos1     = tempCos1;
  5029.  
  5030.         tempCos2     = newCos2 - (updateA*newCos2  + updateB * newSin2);
  5031.         newSin2     = newSin2 - (updateA*newSin2  - updateB * newCos2);
  5032.         newCos2     = tempCos2;
  5033.  
  5034.         ////////////////////////////////////////////////////////////////////////////////
  5035.         // Using vectors we load in, and vectors from previous time through loop, we
  5036.         // generate the vectors:
  5037.         //
  5038.         // vULo1 =     re[k]         im[k]         re[k+1]        im[k+1]
  5039.         // vULo2 =    re[n/2-k]    im[n/2-k]    re[n/2-k-1]    im[n/2-k-1]
  5040.         //
  5041.         // vUHi1 =     re[n/2-k-1]    im[n/2-k-1]    re[n/2-k-2]    im[n/2-k-2]
  5042.         // vUHi2 =    re[k+1]     im[k+1]     re[k+2]        im[k+2]
  5043.         //
  5044.         // with k = 2*i (where i is the loop iterator)
  5045.         ////////////////////////////////////////////////////////////////////////////////
  5046.  
  5047.         vULo1 = vInLoNext;
  5048.         vUHi1 = *pInVecHi--;
  5049.                 
  5050.         vULo2 = vec_sel(vUHi1, vInHiPrev, vHiLoSelect);
  5051.         
  5052.         vInHiPrev = vUHi1;
  5053.         
  5054.         vInLoNext = *pInVecLo++;
  5055.         
  5056.         vUHi2 = vec_sel(vULo1, vInLoNext, vHiLoSelect);
  5057.  
  5058.         ////////////////////////////////////////////////////////////////////////////////
  5059.         //    Calculate sum and difference of vULo1 and vULo2, which are:
  5060.         //
  5061.         // vSumLo = re[k]+re[n/2-k], im[k]+im[n/2-k], re[k+1]+re[n/2-k-1], im[k+1]+im[n/2-k-1]
  5062.         // vDiffLo = re[k]-re[n/2-k], im[k]-im[n/2-k], re[k+1]-re[n/2-k-1], im[k+1]-im[n/2-k-1]
  5063.         ////////////////////////////////////////////////////////////////////////////////
  5064.  
  5065.         vSumLo = vec_add(vULo1, vULo2);        
  5066.         vDiffLo = vec_sub(vULo1, vULo2);        
  5067.  
  5068.         ////////////////////////////////////////////////////////////////////////////////
  5069.         // Next we create a multiplier vector that is:
  5070.         //
  5071.         // vFirstMul = im[k]+im[n/2-k]   re[k]-re[n/2-k]    im[k+1]+im[n/2-k-1]   re[k+1]-re[n/2-k-1]
  5072.         ////////////////////////////////////////////////////////////////////////////////
  5073.  
  5074.         vFirstMul = vec_perm(vSumLo, vDiffLo, vFirstMulPerm);
  5075.         
  5076.         ////////////////////////////////////////////////////////////////////////////////
  5077.         // Next we create a multiplier vector that is:
  5078.         //
  5079.         // vSecondMul = re[k]-re[n/2-k]   im[k]+im[n/2-k]   re[k+1]-re[n/2-k-1]   im[k+1]+im[n/2-k-1]
  5080.         ////////////////////////////////////////////////////////////////////////////////
  5081.         
  5082.         vSecondMul = vec_perm(vSumLo, vDiffLo, vSecondMulPerm);
  5083.         
  5084.         ////////////////////////////////////////////////////////////////////////////////
  5085.         //    We start by generating a result vector
  5086.         // that is:
  5087.         //
  5088.         // vResultLo = re[k]+re[n/2-k]   im[k]-im[n/2-k]   re[k+1]+re[n/2-k-1]   im[k+1]-im[n/2-k-1]
  5089.         ////////////////////////////////////////////////////////////////////////////////
  5090.         
  5091.         vResultLo = vec_perm(vSumLo, vDiffLo, vAdderPerm);
  5092.  
  5093.         ////////////////////////////////////////////////////////////////////////////////
  5094.         // We now calculate:
  5095.         //
  5096.         // vResultLo = 
  5097.         //
  5098.         //        re[k]+re[n/2-k] + (im[k]+im[n/2-k]) * -cos(k*2pi/length),
  5099.         //        im[k]-im[n/2-k] + (re[k]-re[n/2-k]) * cos(k*2pi/length),
  5100.         //        re[k+1]+re[n/2-k-1] + (im[k+1]+im[n/2-k-1]) * -cos((k+1)*2pi/length),
  5101.         //        im[k+1]-im[n/2-k-1] + (re[k+1]-re[n/2-k-1]) * cos((k+1)*2pi/length)
  5102.         //        
  5103.         ////////////////////////////////////////////////////////////////////////////////
  5104.  
  5105.         vResultLo = vec_madd(vCosLo, vFirstMul, vResultLo);
  5106.  
  5107.         ////////////////////////////////////////////////////////////////////////////////
  5108.         // with a negative multiply-subtract, we calculate
  5109.         //
  5110.         // vResultLo = 
  5111.         //
  5112.         //        re[k]+re[n/2-k]     + (im[k]+im[n/2-k]) * -cos(k*2pi/length)            + (re[k]-re[n/2-k]) * -sin(k*2pi/length),
  5113.         //        im[k]-im[n/2-k]     + (re[k]-re[n/2-k]) * cos(k*2pi/length)                + (im[k]+im[n/2-k]) * -sin(k*2pi/length),
  5114.         //        re[k+1]+re[n/2-k-1] + (im[k+1]+im[n/2-k-1]) * -cos((k+1)*2pi/length)    + (re[k+1]-re[n/2-k-1]) * -sin((k+1)*2pi/length),
  5115.         //        im[k+1]-im[n/2-k-1] + (re[k+1]-re[n/2-k-1]) * cos((k+1)*2pi/length)        + (im[k+1]+im[n/2-k-1]) * -sin((k+1)*2pi/length)
  5116.         //        
  5117.         ////////////////////////////////////////////////////////////////////////////////
  5118.  
  5119.         vResultLo = vec_nmsub(vSinLo, vSecondMul, vResultLo);
  5120.  
  5121.  
  5122.         ////////////////////////////////////////////////////////////////////////////////
  5123.         // finally, divide all elements by two multiply by one half).  With this
  5124.         // step finished, we have calculated
  5125.         // e_k + (e^(2pi*i*k/N) * o_k * i), e_(k+1) + (e^(2pi*i*(k+1)/N) * o_(k+1) * i)
  5126.         ////////////////////////////////////////////////////////////////////////////////
  5127.  
  5128.         vResultLo = vec_madd(vResultLo, vOneHalf, vZero);
  5129.         
  5130.         ////////////////////////////////////////////////////////////////////////////////
  5131.         // store this vector back, overwriting source data. 
  5132.         ////////////////////////////////////////////////////////////////////////////////
  5133.  
  5134.         *pOutVecLo++ = vResultLo;
  5135.  
  5136.         ////////////////////////////////////////////////////////////////////////////////
  5137.         // store our new angles to the transition vector, and generate new cos,sin
  5138.         // vectors, using both newly calculated sin&cos, and those already contained
  5139.         // in vCosHi, vSinHi.
  5140.         ////////////////////////////////////////////////////////////////////////////////
  5141.         
  5142.         ((float*)&vFTransition)[0] = newCos2;
  5143.         ((float*)&vFTransition)[1] = newCos1;
  5144.         ((float*)&vFTransition)[2] = newSin2;
  5145.         ((float*)&vFTransition)[3] = newSin1;
  5146.  
  5147.         vCosLo = vec_perm(vCosHi, vFTransition, vNewCosLoPerm);                
  5148.         vSinLo = vec_perm(vSinHi, vFTransition, vNewSinLoPerm);
  5149.                 
  5150.         ////////////////////////////////////////////////////////////////////////////////
  5151.         // calculate sum and difference of vUHi1 and vUHi2
  5152.         ////////////////////////////////////////////////////////////////////////////////
  5153.         
  5154.         vSumHi = vec_add(vUHi1, vUHi2);        
  5155.         vDiffHi = vec_sub(vUHi1, vUHi2);        
  5156.                         
  5157.         ////////////////////////////////////////////////////////////////////////////////
  5158.         // Calculate 
  5159.         // e_k + (e^(2pi*i*k/N) * o_k * i), e_(k+1) + (e^(2pi*i*(k+1)/N) * o_(k+1) * i) 
  5160.         // for high elements in array
  5161.         ////////////////////////////////////////////////////////////////////////////////
  5162.                         
  5163.         vFirstMul = vec_perm(vSumHi, vDiffHi, vFirstMulPerm);
  5164.         vSecondMul = vec_perm(vSumHi, vDiffHi, vSecondMulPerm);
  5165.         
  5166.         vResultHi = vec_perm(vSumHi, vDiffHi, vAdderPerm);
  5167.  
  5168.         vResultHi = vec_madd(vCosHi, vFirstMul, vResultHi);
  5169.         vResultHi = vec_nmsub(vSinHi, vSecondMul, vResultHi);
  5170.         
  5171.         vResultHi = vec_madd(vResultHi, vOneHalf, vZero);
  5172.  
  5173.         ////////////////////////////////////////////////////////////////////////////////
  5174.         // create new angle vectors from our transition vectors for next time
  5175.         // through loop
  5176.         ////////////////////////////////////////////////////////////////////////////////
  5177.  
  5178.         vCosHi = vec_mergeh(vFTransition, vFTransition);        
  5179.         vSinHi = vec_mergel(vFTransition, vFTransition);
  5180.         
  5181.         ////////////////////////////////////////////////////////////////////////////////
  5182.         // store high result, overwriting source
  5183.         ////////////////////////////////////////////////////////////////////////////////
  5184.         
  5185.         *pOutVecHi-- = vResultHi;
  5186.                 
  5187.     }
  5188.  
  5189.     ////////////////////////////////////////////////////////////////////////////////
  5190.     // perform an inverse complex fft on data,
  5191.     // treating it as half-length complex signal.
  5192.     ////////////////////////////////////////////////////////////////////////////////
  5193.     result = FFTComplex(data, length/2, 1);
  5194.  
  5195.     return result;
  5196. }
  5197.  
  5198.  
  5199. ////////////////////////////////////////////////////////////////////////////////
  5200. // scalar implementation of altivec forward real fft above
  5201. ////////////////////////////////////////////////////////////////////////////////
  5202. static OSErr fft_real_forward_scalar(float *data, unsigned long len)
  5203. {
  5204.     OSErr            result = noErr;
  5205.     double            updateA;
  5206.     double            updateB;
  5207.  
  5208.     double            currentCos;
  5209.     double            currentSin;
  5210.  
  5211.     double            tempCos1;
  5212.     
  5213.     float            realLo, realHi;
  5214.     float            imLo, imHi;
  5215.     
  5216.     float            realResultLo, realResultHi;
  5217.     float            imResultLo, imResultHi;
  5218.     
  5219.     float            realDiff, imDiff;
  5220.     float            realSum, imSum;
  5221.         
  5222.     float            *pInLo, *pInHi;
  5223.     
  5224.     long                i;
  5225.     
  5226.     
  5227.     ////////////////////////////////////////////////////////////////////////////////
  5228.     // for length of 0 or 1 we do nothing
  5229.     ////////////////////////////////////////////////////////////////////////////////
  5230.     if (len < 2) return noErr;
  5231.         
  5232.     ////////////////////////////////////////////////////////////////////////////////
  5233.     // perform a forward complex fft on our
  5234.     // real signal data, treating it as a
  5235.     // half-length complex signal.
  5236.     ////////////////////////////////////////////////////////////////////////////////
  5237.     result = FFTComplex(data, len/2, -1);
  5238.  
  5239.     if (result == noErr) {
  5240.  
  5241.         ////////////////////////////////////////////////////////////////////////////////
  5242.         //
  5243.         //    Given c = cos(w) and s = sin(w), if we
  5244.         //    want to find the cos and sin of w plus
  5245.         //    some small angle d, then we can do so
  5246.         //    by defining:
  5247.         //    
  5248.         //    a = 2 * ((sin(d/2)) ^ 2)
  5249.         //    b = sin(d)
  5250.         //    
  5251.         //    Then, we can calculate the cos and sin
  5252.         //    of the updated angle w+d as:
  5253.         //    
  5254.         //    cos(w+d) = c - ac - bs
  5255.         //    sin(w+d) = s - as + bc
  5256.         //    
  5257.         //    We will need to incrementally calculate
  5258.         //    cos(w) and sin(w), so we define the
  5259.         //    following scalar values.  We use scalar
  5260.         //    because we need the precision of doubles,
  5261.         //    and vectors are floats.    
  5262.         //
  5263.         ////////////////////////////////////////////////////////////////////////////////
  5264.                 
  5265.         updateA = sin(PI/len);
  5266.         updateB = sin(2*PI/len);
  5267.         updateA *= updateA*2;
  5268.  
  5269.         ////////////////////////////////////////////////////////////////////////////////
  5270.         // start with sin(0) and cos(0)
  5271.         ////////////////////////////////////////////////////////////////////////////////
  5272.  
  5273.         currentCos = 1;
  5274.         currentSin = 0;    
  5275.     
  5276.         ////////////////////////////////////////////////////////////////////////////////
  5277.         // first, calculate re[0], and re[n/2]. we don't bother to do the sin, cos
  5278.         // multiplies, because we know that they are zero and one.
  5279.         ////////////////////////////////////////////////////////////////////////////////
  5280.                 
  5281.         realResultLo = data[0]+data[1];
  5282.         realResultHi = data[0]-data[1];
  5283.         
  5284.         ////////////////////////////////////////////////////////////////////////////////
  5285.         // store re[0].  We don't calculate im[0] because we know that it is 0.
  5286.         ////////////////////////////////////////////////////////////////////////////////
  5287.         data[0] = realResultLo;
  5288.  
  5289.         ////////////////////////////////////////////////////////////////////////////////
  5290.         // store re[n/2].  We don't calculate im[n/2] because we know it is 0.  We store
  5291.         // re[n/2] in the position of im[0] because we don't want to take up any more
  5292.         // space than the source data, and if we were to store it in the n/2 position,
  5293.         // it would be past the array of source data, which ranges from 0 to (n/2)-1.
  5294.         ////////////////////////////////////////////////////////////////////////////////
  5295.         data[1] = realResultHi;
  5296.         
  5297.         ////////////////////////////////////////////////////////////////////////////////
  5298.         // Start our source pointers to point at re[1] and re[(n/2)-1].
  5299.         ////////////////////////////////////////////////////////////////////////////////
  5300.         pInLo = &data[2];
  5301.         pInHi = &data[len-2];
  5302.  
  5303.         ////////////////////////////////////////////////////////////////////////////////
  5304.         // for each loop iteration, we calculate two complex results (four floats), so
  5305.         // we iterate through the loop len/4 times
  5306.         ////////////////////////////////////////////////////////////////////////////////
  5307.         for (i=0; i<len/4; i++) {
  5308.         
  5309.             ////////////////////////////////////////////////////////////////////////////////
  5310.             // calculate the new sin and cos values
  5311.             ////////////////////////////////////////////////////////////////////////////////
  5312.         
  5313.             tempCos1     = currentCos - (updateA*currentCos  + updateB * currentSin);
  5314.             currentSin     = currentSin - (updateA*currentSin  - updateB * currentCos);
  5315.             currentCos     = tempCos1;
  5316.  
  5317.             ////////////////////////////////////////////////////////////////////////////////
  5318.             // load re[i+1], im[i+1]
  5319.             ////////////////////////////////////////////////////////////////////////////////
  5320.             realLo        = *pInLo;
  5321.             imLo         = *(pInLo+1);
  5322.  
  5323.             ////////////////////////////////////////////////////////////////////////////////
  5324.             // load re[(n/2)-1-i], im[(n/2)-1-i] 
  5325.             ////////////////////////////////////////////////////////////////////////////////
  5326.             realHi         = *pInHi;
  5327.             imHi        = *(pInHi+1);
  5328.             
  5329.             ////////////////////////////////////////////////////////////////////////////////
  5330.             // calculate:
  5331.             // realDiff    = re[i+1]-re[(n/2)-1-i]
  5332.             // realSum    = re[i+1]+re[(n/2)-1-i]
  5333.             ////////////////////////////////////////////////////////////////////////////////
  5334.             realDiff     = realLo-realHi;
  5335.             realSum     = realLo+realHi;
  5336.  
  5337.             ////////////////////////////////////////////////////////////////////////////////
  5338.             // calculate:
  5339.             // imDiff    = im[i+1]-im[(n/2)-1-i]
  5340.             // imSum    = im[i+1]+im[(n/2)-1-i]
  5341.             ////////////////////////////////////////////////////////////////////////////////
  5342.             imDiff         = imLo-imHi;
  5343.             imSum         = imLo+imHi;
  5344.             
  5345.             ////////////////////////////////////////////////////////////////////////////////
  5346.             // calculate:
  5347.             //
  5348.             // realResultLo =     
  5349.             //        re[i+1]+re[(n/2)-1-i] + 
  5350.             //         (im[i+1]+im[(n/2)-1-i]) * cos( (i+1) * 2pi / n ) -
  5351.             //        (re[i+1]-re[(n/2)-1-i]) * sin( (i+1) * 2pi / n )
  5352.             //
  5353.             // imResultLo =     
  5354.             //        im[i+1]-im[(n/2)-1-i] - 
  5355.             //         (re[i+1]-re[(n/2)-1-i]) * cos( (i+1) * 2pi / n ) -
  5356.             //        (im[i+1]+im[(n/2)-1-i]) * sin( (i+1) * 2pi / n )
  5357.             //
  5358.             ////////////////////////////////////////////////////////////////////////////////
  5359.             
  5360.             realResultLo = realSum + (imSum*currentCos) - (realDiff*currentSin);
  5361.             imResultLo = imDiff - (realDiff * currentCos) - (imSum*currentSin);
  5362.             
  5363.             ////////////////////////////////////////////////////////////////////////////////
  5364.             // calculate:
  5365.             //
  5366.             // realResultHi =     
  5367.             //        re[(n/2)-1-i]+re[i+1] +
  5368.             //         (im[(n/2)-1-i]+im[i+1]) * cos( ((n/2)-i-1) * 2pi / n ) -
  5369.             //        (re[(n/2)-1-i]-re[i+1]) * sin( ((n/2)-i-1) * 2pi / n )
  5370.             //
  5371.             // imResultHi =     
  5372.             //        im[(n/2)-1-i]-im[i+1] - 
  5373.             //         (re[(n/2)-1-i]-re[i+1]) * cos( ((n/2)-i-1) * 2pi / n ) -
  5374.             //        (im[(n/2)-1-i]+im[i+1]) * sin( ((n/2)-i-1) * 2pi / n )
  5375.             //
  5376.             // taking advantage of the following:
  5377.             //
  5378.             // sin(  (i+1) * 2pi / n )    =  sin ( ((n/2)-i-1) * 2pi / n )
  5379.             // cos(  (i+1) * 2pi / n )    = -cos ( ((n/2)-i-1) * 2pi / n )
  5380.             // re[(n/2)-1-i]-re[i+1]     = -(re[i+1]-re[(n/2)-1-i])
  5381.             // re[(n/2)-1-i]-re[i+1]     = -(re[i+1]-re[(n/2)-1-i])
  5382.             ////////////////////////////////////////////////////////////////////////////////
  5383.             
  5384.             realResultHi = realSum - (imSum*currentCos) + (realDiff*currentSin);
  5385.             imResultHi = -imDiff - (realDiff * currentCos) - (imSum*currentSin);
  5386.  
  5387.             ////////////////////////////////////////////////////////////////////////////////
  5388.             // store results, advance low pointer forward to next complex element, 
  5389.             // and high pointer backward to previous complex element
  5390.             ////////////////////////////////////////////////////////////////////////////////
  5391.             
  5392.             *pInLo++ = realResultLo/2;        
  5393.             *pInLo++ = imResultLo/2;        
  5394.             *(pInHi+1) = imResultHi/2;        
  5395.             *pInHi = realResultHi/2;
  5396.                     
  5397.             pInHi -= 2;
  5398.         }
  5399.     }
  5400.         
  5401.     return result;    
  5402. }
  5403.  
  5404. ////////////////////////////////////////////////////////////////////////////////
  5405. // scalar implementation of altivec inverse real fft above
  5406. ////////////////////////////////////////////////////////////////////////////////
  5407. static OSErr fft_real_inverse_scalar(float *data, unsigned long len)
  5408. {
  5409.  
  5410.     OSErr            result;
  5411.     double            updateA;
  5412.     double            updateB;
  5413.  
  5414.     double            currentCos;
  5415.     double            currentSin;
  5416.  
  5417.     double            tempCos1;
  5418.     
  5419.     float            realLo, realHi;
  5420.     float            imLo, imHi;
  5421.     
  5422.     float            realResultLo, realResultHi;
  5423.     float            imResultLo, imResultHi;
  5424.     
  5425.     float            realDiff, imDiff;
  5426.     float            realSum, imSum;
  5427.         
  5428.     float            *pInLo, *pInHi;
  5429.     
  5430.     long                i;
  5431.  
  5432.     ////////////////////////////////////////////////////////////////////////////////
  5433.     // for length of 0 or 1 we do nothing
  5434.     ////////////////////////////////////////////////////////////////////////////////
  5435.     if (len < 2) return noErr;
  5436.  
  5437.  
  5438.     ////////////////////////////////////////////////////////////////////////////////
  5439.     // Given c = cos(w) and s = sin(w), if we want to find the cos and sin of w plus
  5440.     // some small angle d, then we can do so by defining:
  5441.     //    
  5442.     // a = 2 * ((sin(d/2)) ^ 2)
  5443.     // b = sin(d)
  5444.     // 
  5445.     // Then, we can calculate the cos and sin of the updated angle w+d as:
  5446.     // 
  5447.     // cos(w+d) = c - ac - bs
  5448.     // sin(w+d) = s - as + bc
  5449.     // 
  5450.     // We will need to incrementally calculate    cos(w) and sin(w), so we define the
  5451.     // following scalar values.  We use scalar    because we need the precision of
  5452.     // doubles, and vectors are floats.    
  5453.     ////////////////////////////////////////////////////////////////////////////////
  5454.             
  5455.     updateA = sin(PI/len);
  5456.     updateB = sin(2*PI/len);
  5457.     updateA *= updateA*2;
  5458.  
  5459.     ////////////////////////////////////////////////////////////////////////////////
  5460.     // start with sin(0) and cos(0)
  5461.     ////////////////////////////////////////////////////////////////////////////////
  5462.  
  5463.     currentCos = 1;
  5464.     currentSin = 0;    
  5465.  
  5466.     ////////////////////////////////////////////////////////////////////////////////
  5467.     // load re[0] and im[0].  Only re[0] is stored -- im[0] is understood to be 0.
  5468.     ////////////////////////////////////////////////////////////////////////////////
  5469.     realLo = data[0];
  5470.     imLo   = 0;
  5471.  
  5472.     ////////////////////////////////////////////////////////////////////////////////
  5473.     // load re[n/2] and im[n/2].  
  5474.     // Only re[n/2] is stored -- im[n/2] is understood to be 0.
  5475.     ////////////////////////////////////////////////////////////////////////////////
  5476.     realHi = data[1];
  5477.     imHi   = 0;                
  5478.  
  5479.     ////////////////////////////////////////////////////////////////////////////////
  5480.     // calculat sum and difference of real & imaginary values
  5481.     ////////////////////////////////////////////////////////////////////////////////
  5482.  
  5483.     realDiff     = realLo-realHi;
  5484.     realSum     = realLo+realHi;
  5485.  
  5486.     imDiff         = imLo-imHi;
  5487.     imSum         = imLo+imHi;
  5488.  
  5489.     ////////////////////////////////////////////////////////////////////////////////
  5490.     // calculate re[0], and im[0]. we don't bother to do the sin, cos multiplies,
  5491.     // because we know that they are zero and one.
  5492.     ////////////////////////////////////////////////////////////////////////////////
  5493.  
  5494.     realResultLo = realSum - imSum;
  5495.     imResultLo = imDiff + realDiff;
  5496.  
  5497.     data[0] = realResultLo/2;
  5498.     data[1] = imResultLo/2;
  5499.  
  5500.     ////////////////////////////////////////////////////////////////////////////////
  5501.     // Start our source pointers to point at re[1] and re[(n/2)-1].
  5502.     ////////////////////////////////////////////////////////////////////////////////
  5503.     pInLo = &data[2];
  5504.     pInHi = &data[len-2];
  5505.     
  5506.     ////////////////////////////////////////////////////////////////////////////////
  5507.     // for each loop iteration, we calculate two complex results (four floats), so
  5508.     // we iterate through the loop len/4 times
  5509.     ////////////////////////////////////////////////////////////////////////////////
  5510.     for (i=0; i<len/4; i++) {
  5511.     
  5512.         ////////////////////////////////////////////////////////////////////////////////
  5513.         // calculate the new sin and cos values
  5514.         ////////////////////////////////////////////////////////////////////////////////
  5515.         tempCos1     = currentCos - (updateA*currentCos  + updateB * currentSin);
  5516.         currentSin     = currentSin - (updateA*currentSin  - updateB * currentCos);
  5517.         currentCos     = tempCos1;
  5518.  
  5519.         ////////////////////////////////////////////////////////////////////////////////
  5520.         // load re[i+1], im[i+1]
  5521.         ////////////////////////////////////////////////////////////////////////////////
  5522.         realLo        = *pInLo;
  5523.         imLo         = *(pInLo+1);
  5524.  
  5525.         ////////////////////////////////////////////////////////////////////////////////
  5526.         // load re[(n/2)-1-i], im[(n/2)-1-i] 
  5527.         ////////////////////////////////////////////////////////////////////////////////
  5528.         realHi         = *pInHi;
  5529.         imHi        = *(pInHi+1);
  5530.         
  5531.         ////////////////////////////////////////////////////////////////////////////////
  5532.         // calculate:
  5533.         // realDiff    = re[i+1]-re[(n/2)-1-i]
  5534.         // realSum    = re[i+1]+re[(n/2)-1-i]
  5535.         ////////////////////////////////////////////////////////////////////////////////
  5536.         realDiff     = realLo-realHi;
  5537.         realSum     = realLo+realHi;
  5538.  
  5539.         ////////////////////////////////////////////////////////////////////////////////
  5540.         // calculate:
  5541.         // imDiff    = im[i+1]-im[(n/2)-1-i]
  5542.         // imSum    = im[i+1]+im[(n/2)-1-i]
  5543.         ////////////////////////////////////////////////////////////////////////////////
  5544.         imDiff         = imLo-imHi;
  5545.         imSum         = imLo+imHi;
  5546.         
  5547.         ////////////////////////////////////////////////////////////////////////////////
  5548.         // calculate:
  5549.         //
  5550.         // realResultLo =     
  5551.         //        re[i+1]+re[(n/2)-1-i] - 
  5552.         //         (im[i+1]+im[(n/2)-1-i]) * cos( (i+1) * 2pi / n ) -
  5553.         //        (re[i+1]-re[(n/2)-1-i]) * sin( (i+1) * 2pi / n )
  5554.         //
  5555.         // imResultLo =     
  5556.         //        im[i+1]-im[(n/2)-1-i] + 
  5557.         //         (re[i+1]-re[(n/2)-1-i]) * cos( (i+1) * 2pi / n ) -
  5558.         //        (im[i+1]+im[(n/2)-1-i]) * sin( (i+1) * 2pi / n )
  5559.         //
  5560.         ////////////////////////////////////////////////////////////////////////////////
  5561.         realResultLo = realSum - (imSum*currentCos) - (realDiff*currentSin);
  5562.         imResultLo = imDiff + (realDiff * currentCos) - (imSum*currentSin);
  5563.  
  5564.         ////////////////////////////////////////////////////////////////////////////////
  5565.         // calculate:
  5566.         //
  5567.         // realResultHi =     
  5568.         //        re[(n/2)-1-i]+re[i+1] -
  5569.         //         (im[(n/2)-1-i]+im[i+1]) * cos( ((n/2)-i-1) * 2pi / n ) -
  5570.         //        (re[(n/2)-1-i]-re[i+1]) * sin( ((n/2)-i-1) * 2pi / n )
  5571.         //
  5572.         // imResultHi =     
  5573.         //        im[(n/2)-1-i]-im[i+1] + 
  5574.         //         (re[(n/2)-1-i]-re[i+1]) * cos( ((n/2)-i-1) * 2pi / n ) -
  5575.         //        (im[(n/2)-1-i]+im[i+1]) * sin( ((n/2)-i-1) * 2pi / n )
  5576.         //
  5577.         // taking advantage of the following:
  5578.         //
  5579.         // sin(  (i+1) * 2pi / n )    =  sin ( ((n/2)-i-1) * 2pi / n )
  5580.         // cos(  (i+1) * 2pi / n )    = -cos ( ((n/2)-i-1) * 2pi / n )
  5581.         // re[(n/2)-1-i]-re[i+1]     = -(re[i+1]-re[(n/2)-1-i])
  5582.         // re[(n/2)-1-i]-re[i+1]     = -(re[i+1]-re[(n/2)-1-i])
  5583.         ////////////////////////////////////////////////////////////////////////////////
  5584.  
  5585.         realResultHi = realSum + (imSum*currentCos) + (realDiff*currentSin);
  5586.         imResultHi = -imDiff + (realDiff * currentCos) - (imSum*currentSin);
  5587.  
  5588.         ////////////////////////////////////////////////////////////////////////////////
  5589.         // store results, advance low pointer forward to next complex element, and
  5590.         // high pointer backward to previous complex element
  5591.         ////////////////////////////////////////////////////////////////////////////////
  5592.  
  5593.         *pInLo++ = realResultLo/2;        
  5594.         *pInLo++ = imResultLo/2;        
  5595.         *(pInHi+1) = imResultHi/2;        
  5596.         *pInHi = realResultHi/2;        
  5597.  
  5598.         pInHi -= 2;
  5599.     
  5600.     }
  5601.  
  5602.     ////////////////////////////////////////////////////////////////////////////////
  5603.     // perform an inverse complex fft on the data.  The resulting data is the 
  5604.     // real-only inverse fft.
  5605.     ////////////////////////////////////////////////////////////////////////////////
  5606.     result = FFTComplex(data, len/2, 1);
  5607.  
  5608.     return result;    
  5609.  
  5610. }
  5611.  
  5612. ////////////////////////////////////////////////////////////////////////////////
  5613. // FFTRealForward
  5614. //
  5615. // Performs a real forward FFT on the data.  A wrapper function for the scalar
  5616. // and AltiVec versions of the forward real FFT, since there is a minimum length
  5617. // for the AltiVec implementation.
  5618. ////////////////////////////////////////////////////////////////////////////////
  5619. OSErr    FFTRealForward(float *data, unsigned long len)
  5620. {
  5621.     if (len < ALTIVEC_REAL_MIN_LENGTH) {
  5622.         return fft_real_forward_scalar(data, len);
  5623.     } else {
  5624.         return fft_real_forward_altivec(data, len);
  5625.     }
  5626. }
  5627.  
  5628. ////////////////////////////////////////////////////////////////////////////////
  5629. // FFTRealInverse
  5630. //
  5631. // Performs a real inverse FFT on the data.  A wrapper function for the scalar
  5632. // and AltiVec versions of the inverse real FFT, since there is a minimum length
  5633. // for the AltiVec implementation.
  5634. ////////////////////////////////////////////////////////////////////////////////
  5635. OSErr    FFTRealInverse(float *data, unsigned long len)
  5636. {
  5637.     if (len < ALTIVEC_REAL_MIN_LENGTH) {
  5638.         return fft_real_inverse_scalar(data, len);
  5639.     } else {
  5640.         return fft_real_inverse_altivec(data, len);
  5641.     }
  5642. }
  5643.  
  5644.  
  5645.  
  5646.  
  5647.  
  5648.  
  5649. #pragma mark -
  5650. #pragma mark 1 D   C O N V O L U T I O N
  5651.  
  5652.  
  5653. ////////////////////////////////////////////////////////////////////////////////
  5654. //    mul_dyadic_real_altivec
  5655. //
  5656. //    Performs a dyadic multiply on the hermitian-order data from
  5657. // a real FFT.  This means that, for a length-N real signal, the complex data
  5658. // that we will be performing the dyadic mul on is expected to be in the order:
  5659. //
  5660. // X = Xr(0) Xr(N/2) Xr(1) Xi(1) Xr(2) Xi(2) ... Xr(N/2-1) Xi(N/2-1)
  5661. //
  5662. //    Signal2 is replaced by Signal2 X Signal1.  Signal1 is unmodified.
  5663. //
  5664. //    
  5665. ////////////////////////////////////////////////////////////////////////////////
  5666. static void mul_dyadic_real_altivec(float *signal1, float *signal2, long len)
  5667. {
  5668.     vector unsigned char         vSwappedPerm;
  5669.     vector float                vSignal1In, vSignal2In;
  5670.     vector float                *pSignal1, *pSignal2;
  5671.     vector float                vSignal2Out;
  5672.     long                        i;    
  5673.     vector float                vMul1, vMul2, vMul3;
  5674.     vector unsigned char        vRealsPerm;
  5675.     vector unsigned char        vImsPerm;
  5676.     vector unsigned char        vSwappedNegatePerm;
  5677.     vector float                vNegSignal2;
  5678.     vector float                vZero = (vector float)(0);
  5679.     
  5680.     float tempreal;
  5681.     float tempim;
  5682.     float real1;
  5683.     float im1;
  5684.     float real2;
  5685.     float im2;
  5686.                 
  5687.     ////////////////////////////////////////////////////////////////////////////////
  5688.     // initialize a permute vector that, given input vectors:
  5689.     //
  5690.     //    X = x0 x1 x2 x3
  5691.     //    Y = y0 y1 y2 y3
  5692.     //
  5693.     // will generate
  5694.     //    Z = x1 x0 x3 y2
  5695.     ////////////////////////////////////////////////////////////////////////////////
  5696.     vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  5697.  
  5698.     ////////////////////////////////////////////////////////////////////////////////
  5699.     // initialize a permute vector that, given input vectors:
  5700.     //
  5701.     //    X = x0 x1 x2 x3
  5702.     //    Y = y0 y1 y2 y3
  5703.     //
  5704.     // will generate
  5705.     //    Z = x0 x0 x2 x2
  5706.     ////////////////////////////////////////////////////////////////////////////////
  5707.     vRealsPerm  = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 8, 9, 10, 11);
  5708.  
  5709.     ////////////////////////////////////////////////////////////////////////////////
  5710.     // initialize a permute vector that, given input vectors:
  5711.     //
  5712.     //    X = x0 x1 x2 x3
  5713.     //    Y = y0 y1 y2 y3
  5714.     //
  5715.     // will generate
  5716.     //    Z = x1 x1 x3 x3
  5717.     ////////////////////////////////////////////////////////////////////////////////
  5718.     vImsPerm  = (vector unsigned char)(4, 5, 6, 7, 4, 5, 6, 7, 12, 13, 14, 15, 12, 13, 14, 15);
  5719.  
  5720.     ////////////////////////////////////////////////////////////////////////////////
  5721.     // initialize a permute vector that, given input vectors:
  5722.     //
  5723.     //    X = x0 x1 x2 x3
  5724.     //    Y = y0 y1 y2 y3
  5725.     //
  5726.     // will generate
  5727.     //    Z = y1 x0 y3 x2
  5728.     ////////////////////////////////////////////////////////////////////////////////
  5729.     vSwappedNegatePerm  = (vector unsigned char)(20, 21, 22, 23, 0, 1, 2, 3, 28, 29, 30, 31, 8, 9, 10, 11);
  5730.  
  5731.     
  5732.     ////////////////////////////////////////////////////////////////////////////////
  5733.     // do simple multiply of real elements Xr(0) and Xr(N/2)
  5734.     ////////////////////////////////////////////////////////////////////////////////
  5735.  
  5736.     signal2[0]     *= signal1[0];
  5737.     signal2[1]     *= signal1[1];
  5738.     
  5739.     ////////////////////////////////////////////////////////////////////////////////
  5740.     // do scalar complex multiply of X(1) with Y(1)
  5741.     ////////////////////////////////////////////////////////////////////////////////
  5742.  
  5743.     real1        = signal1[2];
  5744.     real2         = signal2[2];
  5745.     im1         = signal1[3];
  5746.     im2         = signal2[3];
  5747.     
  5748.     tempreal    = (real1*real2) - (im1*im2);
  5749.     tempim         = (real1*im2) + (real2*im1);
  5750.     
  5751.     signal2[2]    = tempreal;
  5752.     signal2[3]     = tempim;
  5753.  
  5754.     ////////////////////////////////////////////////////////////////////////////////
  5755.     // the rest of the data is complex, and aligned on a vector boundary, so we
  5756.     // will perform all subsequent multiplies in the vector domain.  We start
  5757.     // by setting two pointers to point at the start of the remaining signal
  5758.     ////////////////////////////////////////////////////////////////////////////////
  5759.  
  5760.     pSignal1 = ((vector float*)signal1)+1;
  5761.     pSignal2 = ((vector float*)signal2)+1;
  5762.     
  5763.     ////////////////////////////////////////////////////////////////////////////////
  5764.     // we loop through all remaining complex elements, performing a complex multiply
  5765.     ////////////////////////////////////////////////////////////////////////////////
  5766.  
  5767.     for (i=1; i<len/4; i++) {
  5768.     
  5769.         ////////////////////////////////////////////////////////////////////////////////
  5770.         // load in a vector from each of signal1 and signal2
  5771.         ////////////////////////////////////////////////////////////////////////////////
  5772.  
  5773.         vSignal1In = *pSignal1++;
  5774.         vSignal2In = *pSignal2;
  5775.         
  5776.         ////////////////////////////////////////////////////////////////////////////////
  5777.         // negate signal 2, so we have negative values necessary for our multiplies
  5778.         ////////////////////////////////////////////////////////////////////////////////
  5779.  
  5780.         vNegSignal2 = vec_sub(vZero, vSignal2In);
  5781.  
  5782.         ////////////////////////////////////////////////////////////////////////////////
  5783.         // set up multiplicand vectors.  Since we are multiplying complex numbers, we
  5784.         // need to do more than just call a multiply routine.  Given two complex numbers
  5785.         // x = (xr, xi) and y = (yr, yi), then the product z = (zr, zi) = x*y is defined
  5786.         // as:
  5787.         // 
  5788.         //    zr = xr*yr - xi*yi
  5789.         //    zi = xr*yi + xi*yr
  5790.         //
  5791.         // to perform this multiplication, we generate four multiplicand vectors. If we
  5792.         // consider our input vectors X and Y, they each contain two complex numbers:
  5793.         //
  5794.         //    X = (x1r, x1i, x2r, x2i)
  5795.         //    Y = (y1r, y1i, y2r, y2i)
  5796.         //
  5797.         // then we want to generate a new output Z vector:
  5798.         //
  5799.         //    Z = (x1r*y1r - x1i*y1i, x1r*y1i + x1i*y1r, x2r*y2r - x2i*y2i, x2r*y2i + x2i*y2r)
  5800.         //
  5801.         //    So, we need to have multiplicand vectors:
  5802.         //
  5803.         //    M1 =     x1r        x1r        x2r        x2r
  5804.         //    M2 =     x1i        x1i        x2i     x2i
  5805.         //    M3 =    -y1i    y1r        -y2i    y2r
  5806.         //    M4 =     y1r        y1i        y2r        y2i
  5807.         //
  5808.         //    We can then generate our Z vector with a vector mul and a vector mul-add.
  5809.         ////////////////////////////////////////////////////////////////////////////////
  5810.         
  5811.         vMul1 = vec_perm(vSignal1In, vSignal1In, vRealsPerm);
  5812.         vMul2 = vec_perm(vSignal1In, vSignal1In, vImsPerm);
  5813.         vMul3 = vec_perm(vSignal2In, vNegSignal2, vSwappedNegatePerm);
  5814.         
  5815.         vSignal2Out = vec_madd(vMul1, vSignal2In, vZero);
  5816.         vSignal2Out = vec_madd(vMul2, vMul3, vSignal2Out);
  5817.         
  5818.         ////////////////////////////////////////////////////////////////////////////////
  5819.         // store product vector back to current position in signal 2
  5820.         ////////////////////////////////////////////////////////////////////////////////
  5821.  
  5822.         *pSignal2++ = vSignal2Out;
  5823.         
  5824.     }
  5825. }
  5826.  
  5827.  
  5828. ////////////////////////////////////////////////////////////////////////////////
  5829. //    mul_dyadic_complex_altivec
  5830. //
  5831. // Performs a dyadic multiply on two complex signals. 
  5832. //    
  5833. //    Signal2 is replaced by Signal2 X Signal1.  Signal1 is unmodified.
  5834. //
  5835. ////////////////////////////////////////////////////////////////////////////////
  5836. static void mul_dyadic_complex_altivec(float *signal1, float *signal2, long len)
  5837. {
  5838.     vector unsigned char         vSwappedPerm;
  5839.     vector float                vSignal1In, vSignal2In;
  5840.     vector float                *pSignal1, *pSignal2;
  5841.     vector float                vSignal2Out;
  5842.     long                        i;    
  5843.     vector float                vMul1, vMul2, vMul3;
  5844.     vector unsigned char        vRealsPerm;
  5845.     vector unsigned char        vImsPerm;
  5846.     vector unsigned char        vSwappedNegatePerm;
  5847.     vector float                vNegSignal2;
  5848.     vector float                vZero = (vector float)(0);
  5849.                 
  5850.     ////////////////////////////////////////////////////////////////////////////////
  5851.     // initialize a permute vector that, given input vectors:
  5852.     //
  5853.     //    X = x0 x1 x2 x3
  5854.     //    Y = y0 y1 y2 y3
  5855.     //
  5856.     // will generate
  5857.     //    Z = x1 x0 x3 y2
  5858.     ////////////////////////////////////////////////////////////////////////////////
  5859.     vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  5860.  
  5861.     ////////////////////////////////////////////////////////////////////////////////
  5862.     // initialize a permute vector that, given input vectors:
  5863.     //
  5864.     //    X = x0 x1 x2 x3
  5865.     //    Y = y0 y1 y2 y3
  5866.     //
  5867.     // will generate
  5868.     //    Z = x0 x0 x2 x2
  5869.     ////////////////////////////////////////////////////////////////////////////////
  5870.     vRealsPerm  = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 8, 9, 10, 11);
  5871.  
  5872.     ////////////////////////////////////////////////////////////////////////////////
  5873.     // initialize a permute vector that, given input vectors:
  5874.     //
  5875.     //    X = x0 x1 x2 x3
  5876.     //    Y = y0 y1 y2 y3
  5877.     //
  5878.     // will generate
  5879.     //    Z = x1 x1 x3 x3
  5880.     ////////////////////////////////////////////////////////////////////////////////
  5881.     vImsPerm  = (vector unsigned char)(4, 5, 6, 7, 4, 5, 6, 7, 12, 13, 14, 15, 12, 13, 14, 15);
  5882.  
  5883.     ////////////////////////////////////////////////////////////////////////////////
  5884.     // initialize a permute vector that, given input vectors:
  5885.     //
  5886.     //    X = x0 x1 x2 x3
  5887.     //    Y = y0 y1 y2 y3
  5888.     //
  5889.     // will generate
  5890.     //    Z = y1 x0 y3 x2
  5891.     ////////////////////////////////////////////////////////////////////////////////
  5892.     vSwappedNegatePerm  = (vector unsigned char)(20, 21, 22, 23, 0, 1, 2, 3, 28, 29, 30, 31, 8, 9, 10, 11);
  5893.     
  5894.     ////////////////////////////////////////////////////////////////////////////////
  5895.     // initialize pointers to start at beginning of both signals
  5896.     ////////////////////////////////////////////////////////////////////////////////
  5897.  
  5898.     pSignal1 = (vector float*)signal1;
  5899.     pSignal2 = (vector float*)signal2;
  5900.     
  5901.     ////////////////////////////////////////////////////////////////////////////////
  5902.     // loop through all elements one vector (two complex entries) at a time.
  5903.     ////////////////////////////////////////////////////////////////////////////////
  5904.  
  5905.  
  5906.     for (i=0; i<len/2; i++) {
  5907.  
  5908.         ////////////////////////////////////////////////////////////////////////////////
  5909.         // load in a vector from each of signal1 and signal2
  5910.         ////////////////////////////////////////////////////////////////////////////////
  5911.  
  5912.         vSignal1In = *pSignal1++;
  5913.         vSignal2In = *pSignal2;
  5914.                 
  5915.         ////////////////////////////////////////////////////////////////////////////////
  5916.         // negate signal 2, so we have negative values necessary for our multiplies
  5917.         ////////////////////////////////////////////////////////////////////////////////
  5918.  
  5919.         vNegSignal2 = vec_sub(vZero, vSignal2In);
  5920.         
  5921.         ////////////////////////////////////////////////////////////////////////////////
  5922.         // set up multiplicand vectors.  Since we are multiplying complex numbers, we
  5923.         // need to do more than just call a multiply routine.  Given two complex numbers
  5924.         // x = (xr, xi) and y = (yr, yi), then the product z = (zr, zi) = x*y is defined
  5925.         // as:
  5926.         // 
  5927.         //    zr = xr*yr - xi*yi
  5928.         //    zi = xr*yi + xi*yr
  5929.         //
  5930.         // to perform this multiplication, we generate four multiplicand vectors. If we
  5931.         // consider our input vectors X and Y, they each contain two complex numbers:
  5932.         //
  5933.         //    X = (x1r, x1i, x2r, x2i)
  5934.         //    Y = (y1r, y1i, y2r, y2i)
  5935.         //
  5936.         // then we want to generate a new output Z vector:
  5937.         //
  5938.         //    Z = (x1r*y1r - x1i*y1i, x1r*y1i + x1i*y1r, x2r*y2r - x2i*y2i, x2r*y2i + x2i*y2r)
  5939.         //
  5940.         //    So, we need to have multiplicand vectors:
  5941.         //
  5942.         //    M1 =     x1r        x1r        x2r        x2r
  5943.         //    M2 =     x1i        x1i        x2i     x2i
  5944.         //    M3 =    -y1i    y1r        -y2i    y2r
  5945.         //    M4 =     y1r        y1i        y2r        y2i
  5946.         //
  5947.         //    We can then generate our Z vector with a vector mul and a vector mul-add.
  5948.         ////////////////////////////////////////////////////////////////////////////////
  5949.  
  5950.         vMul1 = vec_perm(vSignal1In, vSignal1In, vRealsPerm);
  5951.         vMul2 = vec_perm(vSignal1In, vSignal1In, vImsPerm);
  5952.         vMul3 = vec_perm(vSignal2In, vNegSignal2, vSwappedNegatePerm);
  5953.         
  5954.         vSignal2Out = vec_madd(vMul1, vSignal2In, vZero);
  5955.         vSignal2Out = vec_madd(vMul2, vMul3, vSignal2Out);
  5956.         
  5957.         ////////////////////////////////////////////////////////////////////////////////
  5958.         // store product vector back to current position in signal 2
  5959.         ////////////////////////////////////////////////////////////////////////////////
  5960.  
  5961.         *pSignal2++ = vSignal2Out;
  5962.         
  5963.     }
  5964.  
  5965. }
  5966.  
  5967. ////////////////////////////////////////////////////////////////////////////////
  5968. //    ConvolveComplexAltivec
  5969. //
  5970. //    calculates the convolution of signal1 and signal2, both of length n.
  5971. // This is done by performing a forward FFT on both signals, then calculating
  5972. // the dyadic mul of the two resulting signals.  Finally, an inverse FFT is
  5973. // performed on the result of the dyadic mul.
  5974. //
  5975. //    signal2 is replaced by the convolution of signal1 and signal2. signal1
  5976. // is replaced by the FFT of signal1.
  5977. //
  5978. ////////////////////////////////////////////////////////////////////////////////
  5979. OSErr ConvolveComplexAltivec( float *    pSignal1,    float *    pSignal2,     int   n)
  5980. {
  5981.     OSErr        result = noErr;
  5982.     
  5983.     ////////////////////////////////////////////////////////////////////////////////
  5984.     // if the length is great enough, then we want to perform a columnwise matrix
  5985.     // FFT instead of a standard complex FFT. One leaves the data in normal order,
  5986.     // the other leaves it in columnwise order. (The motivation is that the 
  5987.     // columnwise FFT is considerably faster for longer run lengths.)
  5988.     
  5989.     // We will then be peforming a dyadic mul (for which order doesn't matter). 
  5990.     // Finally, we will perform an inverse FFT, and if we used the columnwise forward
  5991.     // FFT (which left data in columnwise order) then we will use the columnwise
  5992.     // inverse FFT, which will expect the input data in columnwise order.
  5993.     ////////////////////////////////////////////////////////////////////////////////
  5994.     
  5995.     if (n >= ALTIVEC_COLUMNWISE_FFT_BREAKOVER) {
  5996.  
  5997.         ////////////////////////////////////////////////////////////////////////////////
  5998.         // perform matrix fft on data which will leave data in columnwise order.
  5999.         ////////////////////////////////////////////////////////////////////////////////
  6000.         
  6001.         result = fft_matrix_forward_columnwise(pSignal1, n);
  6002.  
  6003.     } else {
  6004.  
  6005.         ////////////////////////////////////////////////////////////////////////////////
  6006.         // perform standard complex fft on data
  6007.         ////////////////////////////////////////////////////////////////////////////////
  6008.  
  6009.         result = FFTComplex(pSignal1, n, -1);
  6010.  
  6011.     }
  6012.     
  6013.     if (result == noErr) {
  6014.  
  6015.         if (n >= ALTIVEC_COLUMNWISE_FFT_BREAKOVER) {
  6016.  
  6017.             ////////////////////////////////////////////////////////////////////////////////
  6018.             // perform matrix fft on data which will leave data in columnwise order.
  6019.             ////////////////////////////////////////////////////////////////////////////////
  6020.  
  6021.             result = fft_matrix_forward_columnwise(pSignal2, n);
  6022.  
  6023.         } else {
  6024.  
  6025.             ////////////////////////////////////////////////////////////////////////////////
  6026.             // perform standard complex fft on data
  6027.             ////////////////////////////////////////////////////////////////////////////////
  6028.  
  6029.             result = FFTComplex(pSignal2, n, -1);
  6030.         }
  6031.  
  6032.         if (result == noErr) {
  6033.         
  6034.             ////////////////////////////////////////////////////////////////////////////////
  6035.             // perform dyadic multiply on result of both FFTs, replacing signal2 with
  6036.             // the result
  6037.             ////////////////////////////////////////////////////////////////////////////////
  6038.  
  6039.             mul_dyadic_complex_altivec(pSignal1, pSignal2, n);
  6040.             
  6041.             ////////////////////////////////////////////////////////////////////////////////
  6042.             // perform inverse FFT on signal2, which will yield a result that is the
  6043.             // convolution of signal1 and signal2.
  6044.             ////////////////////////////////////////////////////////////////////////////////
  6045.  
  6046.             if (n >= ALTIVEC_COLUMNWISE_FFT_BREAKOVER) {
  6047.  
  6048.                 ////////////////////////////////////////////////////////////////////////////////
  6049.                 // perform inverse matrix fft on data which expects input data to be in
  6050.                 // columnwise order.
  6051.                 ////////////////////////////////////////////////////////////////////////////////
  6052.  
  6053.                 result = fft_matrix_inverse_columnwise(pSignal2, n);
  6054.                 
  6055.             } else {
  6056.  
  6057.                 ////////////////////////////////////////////////////////////////////////////////
  6058.                 // perform standard inverse complex fft on data
  6059.                 ////////////////////////////////////////////////////////////////////////////////
  6060.  
  6061.                 result = FFTComplex(pSignal2, n, 1);
  6062.             }
  6063.     
  6064.         }
  6065.     
  6066.     }
  6067.  
  6068.     return result; 
  6069. }
  6070.  
  6071.  
  6072.  
  6073. ////////////////////////////////////////////////////////////////////////////////
  6074. //    ConvolveRealAltivec
  6075. //
  6076. //    calculates the convolution of signal1 and signal2, both of length n.
  6077. // This is done by performing a forward FFT on both signals, then calculating
  6078. // the dyadic mul of the two resulting signals.  Finally, an inverse FFT is
  6079. // performed on the result of the dyadic mul.
  6080. //
  6081. //    signal2 is replaced by the convolution of signal1 and signal2. signal1
  6082. // is replaced by the FFT of signal1.
  6083. //
  6084. ////////////////////////////////////////////////////////////////////////////////
  6085. OSErr ConvolveRealAltivec(float *    pSignal1, float *    pSignal2, int length)
  6086. {
  6087.     OSErr    result;
  6088.     
  6089.     
  6090.     ////////////////////////////////////////////////////////////////////////////////
  6091.     // perform real FFT on signal1
  6092.     ////////////////////////////////////////////////////////////////////////////////
  6093.  
  6094.     result = FFTRealForward(pSignal1, length);
  6095.     
  6096.     if (result == noErr) {
  6097.  
  6098.         ////////////////////////////////////////////////////////////////////////////////
  6099.         // perform real FFT on signal2
  6100.         ////////////////////////////////////////////////////////////////////////////////
  6101.  
  6102.         result = FFTRealForward(pSignal2, length);
  6103.         
  6104.         if (result == noErr) {
  6105.  
  6106.             ////////////////////////////////////////////////////////////////////////////////
  6107.             // perform dyadic mul on result of both FFTs, which are stored in hermitian
  6108.             // order.
  6109.             ////////////////////////////////////////////////////////////////////////////////
  6110.  
  6111.             mul_dyadic_real_altivec(pSignal1, pSignal2, length);
  6112.  
  6113.             ////////////////////////////////////////////////////////////////////////////////
  6114.             // perform inverse real FFT on result of dyadic mul, which produces the 
  6115.             // convolution of signal1 and signal2.
  6116.             ////////////////////////////////////////////////////////////////////////////////
  6117.  
  6118.             result = FFTRealInverse(pSignal2, length);
  6119.         
  6120.         }
  6121.         
  6122.     }
  6123.     
  6124.     return result;
  6125.     
  6126. }
  6127.  
  6128.  
  6129.  
  6130. #pragma mark -
  6131. #pragma mark 2 D   F F T
  6132.  
  6133. ////////////////////////////////////////////////////////////////////////////////
  6134. //    FFT2DComplex
  6135. //
  6136. //    performs a 2-dimensional FFT on a complex 2D (width X height) signal. If
  6137. // iflag is -1, a forward FFT is performed, otherwise an inverse FFT is
  6138. // performed.
  6139. //
  6140. //    **NOTE** that implementation details demand that width >= 2 and height >=2
  6141. //
  6142. ////////////////////////////////////////////////////////////////////////////////
  6143.  
  6144. OSErr    FFT2DComplex(float *pData, unsigned long width, unsigned long height, long iflag)
  6145. {
  6146.     long        i, j;
  6147.     float        *pRow;
  6148.     long        rowPower;
  6149.     long        colPower;
  6150.     Handle        rowBufferHandle = nil;
  6151.     OSErr        result = noErr;
  6152.  
  6153.     ////////////////////////////////////////////////////////////////////////////////
  6154.     // ensure that width & height are at least 2 (required for algorithm impl.)
  6155.     ////////////////////////////////////////////////////////////////////////////////
  6156.     if ((width < 2) || (height < 2)) {
  6157.         return paramErr;    
  6158.     }
  6159.  
  6160.     ////////////////////////////////////////////////////////////////////////////////
  6161.     // data must be 16-byte aligned because of vector load/store requirements
  6162.     ////////////////////////////////////////////////////////////////////////////////
  6163.     if (((long)pData) & 0x0F) {
  6164.         return paramErr;
  6165.     }
  6166.                    
  6167.     rowPower = log2max(width);
  6168.     colPower = log2max(height);
  6169.  
  6170.     ////////////////////////////////////////////////////////////////////////////////
  6171.     // width must be an exact power of 2
  6172.     ////////////////////////////////////////////////////////////////////////////////
  6173.     if ((1 << rowPower) != width) {
  6174.         return paramErr;
  6175.     }
  6176.  
  6177.     ////////////////////////////////////////////////////////////////////////////////
  6178.     // height must be an exact power of 2
  6179.     ////////////////////////////////////////////////////////////////////////////////
  6180.     if ((1 << colPower) != height) {
  6181.         return paramErr;
  6182.     }
  6183.     
  6184.     ////////////////////////////////////////////////////////////////////////////////
  6185.     // allocate a buffer for column ferrying of two columns.
  6186.     ////////////////////////////////////////////////////////////////////////////////
  6187.  
  6188.     rowBufferHandle = NewHandle(2*2*sizeof(float)*height);
  6189.     
  6190.     result = MemError();
  6191.     
  6192.     if (result == noErr) {
  6193.         vector float            *pCurrentColumn;
  6194.         vector float            vIn1, vIn2;
  6195.         vector float            vOut1, vOut2;
  6196.         vector unsigned char    vMergeHiPairPerm;
  6197.         vector unsigned char    vMergeLoPairPerm;
  6198.         vector float            *pSplit1, *pSplit2;
  6199.         float                    *pFFT1, *pFFT2;
  6200.         
  6201.         
  6202.         ////////////////////////////////////////////////////////////////////////////////
  6203.         // perform an FFT on every row of the 2D array
  6204.         ////////////////////////////////////////////////////////////////////////////////
  6205.         pRow = pData;
  6206.         
  6207.         for (i=0; i<height; i++) {
  6208.             result = FFTComplex(pRow+i*(width*2), width, iflag);
  6209.             if (result != noErr) break;
  6210.         }
  6211.         
  6212.         if (result == noErr) {        
  6213.             ////////////////////////////////////////////////////////////////////////////////
  6214.             // initialize a permute vector that, given input vectors:
  6215.             //
  6216.             //    X = x0 x1 x2 x3
  6217.             //    Y = y0 y1 y2 y3
  6218.             //
  6219.             // will generate
  6220.             //    Z = x0 x1 y0 y1
  6221.             ////////////////////////////////////////////////////////////////////////////////
  6222.             vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  6223.  
  6224.             ////////////////////////////////////////////////////////////////////////////////
  6225.             // initialize a permute vector that, given input vectors:
  6226.             //
  6227.             //    X = x0 x1 x2 x3
  6228.             //    Y = y0 y1 y2 y3
  6229.             //
  6230.             // will generate
  6231.             //    Z = x2 x3 y2 y3
  6232.             ////////////////////////////////////////////////////////////////////////////////
  6233.             vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  6234.             
  6235.                     
  6236.             ////////////////////////////////////////////////////////////////////////////////
  6237.             // we now loop through all columns, two columns at a time, and perform column
  6238.             // ferrying FFTs on the columns.  We first copy the columns to a separate
  6239.             // buffer, then perform the FFTs, and finally copy them back to their original
  6240.             // column positions.
  6241.             ////////////////////////////////////////////////////////////////////////////////
  6242.  
  6243.             for (i=0; i<width/2; i++) {
  6244.             
  6245.                 ////////////////////////////////////////////////////////////////////////////////
  6246.                 // point at top of current columns
  6247.                 ////////////////////////////////////////////////////////////////////////////////
  6248.                 pCurrentColumn = ((vector float*)pData) + i;        
  6249.  
  6250.                 ////////////////////////////////////////////////////////////////////////////////
  6251.                 // initialize pointers in temporary buffer for storing copied columns.
  6252.                 ////////////////////////////////////////////////////////////////////////////////
  6253.                 pSplit1 = *(vector float**)rowBufferHandle;
  6254.                 pSplit2 = pSplit1 + height / 2;
  6255.                     
  6256.                 ////////////////////////////////////////////////////////////////////////////////
  6257.                 // loop through all rows in the current column, copying elements to the
  6258.                 // temporary buffer.  We load two rows at a time, and permute the vectors
  6259.                 // to create a single vector that contains the appropriate column elements
  6260.                 // from both rows.
  6261.                 ////////////////////////////////////////////////////////////////////////////////
  6262.  
  6263.                 for (j=0; j < height/2; j++) {
  6264.  
  6265.                     ////////////////////////////////////////////////////////////////////////////////
  6266.                     // read in two rows worth of vectors (two rows X two columns)
  6267.                     ////////////////////////////////////////////////////////////////////////////////
  6268.  
  6269.                     vIn1 = *pCurrentColumn;
  6270.                     pCurrentColumn += width/2;
  6271.                     vIn2 = *pCurrentColumn;
  6272.                     pCurrentColumn += width/2;
  6273.                     
  6274.                     ////////////////////////////////////////////////////////////////////////////////
  6275.                     // permute the vectors so that the two left column entries are in one vector
  6276.                     // and the two right column entries are in one vector
  6277.                     ////////////////////////////////////////////////////////////////////////////////
  6278.  
  6279.                     vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  6280.                     vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  6281.                     
  6282.                     ////////////////////////////////////////////////////////////////////////////////
  6283.                     // store the split columns to the appropriate buffers
  6284.                     ////////////////////////////////////////////////////////////////////////////////
  6285.  
  6286.                     *pSplit1++ = vOut1;
  6287.                     *pSplit2++ = vOut2;
  6288.  
  6289.                 }
  6290.  
  6291.                 ////////////////////////////////////////////////////////////////////////////////
  6292.                 // perform FFTs on the two columns of data that we have copied to the temp
  6293.                 // buffer
  6294.                 ////////////////////////////////////////////////////////////////////////////////
  6295.  
  6296.                 pFFT1 = *(float **)rowBufferHandle;
  6297.                 pFFT2 = pFFT1 + 2*height;
  6298.                 
  6299.                 result = FFTComplex(pFFT1, height, iflag);
  6300.                 if (result != noErr) break;
  6301.                 
  6302.                 result = FFTComplex(pFFT2, height, iflag);
  6303.                 if (result != noErr) break;
  6304.                     
  6305.                 ////////////////////////////////////////////////////////////////////////////////
  6306.                 // point at the beginning of the two copied column buffers, and at the top
  6307.                 // of the columns in the matrix where we will store them back.
  6308.                 ////////////////////////////////////////////////////////////////////////////////
  6309.  
  6310.                 pSplit1 = *(vector float**)rowBufferHandle;
  6311.                 pSplit2 = pSplit1 + height / 2;
  6312.                 pCurrentColumn = ((vector float*)pData) + i;
  6313.  
  6314.                 ////////////////////////////////////////////////////////////////////////////////
  6315.                 // loop through all of the column entries that are stored in the temp buffer,
  6316.                 // and merge them to be stored back into the columns of the matrix. 
  6317.                 ////////////////////////////////////////////////////////////////////////////////
  6318.  
  6319.                 for (j=0; j < height/2; j++) {
  6320.                 
  6321.                     ////////////////////////////////////////////////////////////////////////////////
  6322.                     // get two vectors of column data
  6323.                     ////////////////////////////////////////////////////////////////////////////////
  6324.  
  6325.                     vIn1 = *pSplit1++;
  6326.                     vIn2 = *pSplit2++;
  6327.                     
  6328.                     ////////////////////////////////////////////////////////////////////////////////
  6329.                     // turn them into row vectors
  6330.                     ////////////////////////////////////////////////////////////////////////////////
  6331.  
  6332.                     vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  6333.                     vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  6334.                                     
  6335.                     ////////////////////////////////////////////////////////////////////////////////
  6336.                     // store row vectors back into the matrix
  6337.                     ////////////////////////////////////////////////////////////////////////////////
  6338.  
  6339.                     *pCurrentColumn = vOut1;
  6340.                     pCurrentColumn += width / 2;
  6341.                     *pCurrentColumn = vOut2;                
  6342.                     pCurrentColumn += width / 2;
  6343.                                     
  6344.                 }
  6345.                     
  6346.             }
  6347.             
  6348.         }    
  6349.                     
  6350.     }
  6351.  
  6352.     if (rowBufferHandle) {
  6353.         DisposeHandle(rowBufferHandle);
  6354.     }
  6355.  
  6356.     return result;
  6357.  
  6358. }
  6359.  
  6360. ////////////////////////////////////////////////////////////////////////////////
  6361. //    FFT2DRealForward
  6362. //
  6363. //    performs a 2-dimensional FFT on a real 2D (width X height) signal. 
  6364. //     Resulting data is stored in a matrix in the following arrangement:
  6365. //
  6366. //    X = 
  6367. //        
  6368. //    Xr(0,0)        Xr(0, W/2)        Xr(0,1)    Xi(0,1)    Xr(0,2)    Xi(0,2)    ... Xr(0,W/2-1) Xi(0,W/2-1)
  6369. //    Xr(H/2,0)    Xr(H/2,W/2)        Xr(1,1)    Xi(1,1)    Xr(1,2)    Xi(1,2)    ... Xr(1,W/2-1) Xi(1,W/2-1)
  6370. //    Xr(1,0)        Xr(1,W/2)        Xr(2,1)    Xi(2,1)    Xr(2,2)    Xi(2,2)    ... Xr(2,W/2-1) Xi(2,W/2-1)
  6371. //    Xi(1,0)        Xi(1,W/2)        Xr(3,1)    Xi(3,1)    Xr(3,2)    Xi(3,2)    ... Xr(3,W/2-1) Xi(3,W/2-1)
  6372. //    .
  6373. //    .
  6374. //    .
  6375. //    Xr(H/2-1,0)    Xr(H/2-1,W/2)    Xr(H-2,1)    Xi(H-2,1)    ...         Xr(H-2,W/2-1) Xi(H-2,W/2-1)
  6376. //    Xi(H/2-1,0)    Xi(H/2-1,W/2)    Xr(H-1,1)    Xi(H-1,1)    ...         Xr(H-1,W/2-1) Xi(H-1,W/2-1)
  6377. //
  6378. // We perform the 2D fft by taking the following steps.  First, we perform a
  6379. // forward real fft on each row. This results in the first two entries of each
  6380. // row being the real elements of X[0] and X[m/2], given m columns.  The remaining
  6381. // entries in the row are the complex elements of X[1] ... X[m-1].  Next we
  6382. // perform a real FFT on the first two columns of the matrix (which are real data).
  6383. // finally, we perform a complex FFT on the remaining columns of complex data.    
  6384. //
  6385. //    **NOTE** that implementation details demand that width >= 8 and height >=4
  6386. //
  6387. ////////////////////////////////////////////////////////////////////////////////
  6388. OSErr    FFT2DRealForward(float *data, unsigned long width, unsigned long height)
  6389. {
  6390.     long        i, j;
  6391.     float        *pRow;
  6392.     long        rowPower;
  6393.     long        colPower;
  6394.     Handle        rowBufferHandle = nil;
  6395.     OSErr        result = noErr;
  6396.                    
  6397.     rowPower = log2max(width);
  6398.     colPower = log2max(height);
  6399.  
  6400.  
  6401.     ////////////////////////////////////////////////////////////////////////////////
  6402.     // ensure that width & height are at least 4 (required for algorithm impl)
  6403.     ////////////////////////////////////////////////////////////////////////////////
  6404.     if ((width < 8) || (height < 4)) {
  6405.         return paramErr;    
  6406.     }
  6407.     
  6408.     ////////////////////////////////////////////////////////////////////////////////
  6409.     // width must be an exact power of 2
  6410.     ////////////////////////////////////////////////////////////////////////////////
  6411.  
  6412.     if ((1 << rowPower) != width) {
  6413.         return paramErr;
  6414.     }
  6415.  
  6416.     ////////////////////////////////////////////////////////////////////////////////
  6417.     // height must be an exact power of 2
  6418.     ////////////////////////////////////////////////////////////////////////////////
  6419.  
  6420.     if ((1 << colPower) != height) {
  6421.         return paramErr;
  6422.     }
  6423.     
  6424.     ////////////////////////////////////////////////////////////////////////////////
  6425.     // allocate a buffer for column ferrying of two columns.
  6426.     ////////////////////////////////////////////////////////////////////////////////
  6427.  
  6428.     rowBufferHandle = NewHandle(2*2*sizeof(float)*height);
  6429.  
  6430.     
  6431.     result = MemError();
  6432.     
  6433.     if (result == noErr) {
  6434.         vector float            *pCurrentColumn;
  6435.         vector float            vIn1, vIn2, vIn3, vIn4;
  6436.         vector float            vOut1, vOut2, vOut3, vOut4;
  6437.         vector unsigned char    vMergeHiPairPerm;
  6438.         vector unsigned char    vMergeLoPairPerm;
  6439.         vector float            *pSplit1, *pSplit2, *pSplit3;
  6440.         float                    *pFFT1, *pFFT2;
  6441.         vector float            vTemp1, vTemp2;
  6442.         
  6443.         ////////////////////////////////////////////////////////////////////////////////
  6444.         // perform standard forward real fft on every row
  6445.         ////////////////////////////////////////////////////////////////////////////////
  6446.  
  6447.         pRow = data;
  6448.         
  6449.         for (i=0; i<height; i++) {
  6450.             result = FFTRealForward(pRow+i*(width), width);
  6451.             if (result != noErr) break;
  6452.         }
  6453.  
  6454.         if (result == noErr) {
  6455.             ////////////////////////////////////////////////////////////////////////////////
  6456.             // initialize a permute vector that, given input vectors:
  6457.             //
  6458.             //    X = x0 x1 x2 x3
  6459.             //    Y = y0 y1 y2 y3
  6460.             //
  6461.             // will generate
  6462.             //    Z = x0 x1 y0 y1
  6463.             ////////////////////////////////////////////////////////////////////////////////
  6464.             vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  6465.  
  6466.             ////////////////////////////////////////////////////////////////////////////////
  6467.             // initialize a permute vector that, given input vectors:
  6468.             //
  6469.             //    X = x0 x1 x2 x3
  6470.             //    Y = y0 y1 y2 y3
  6471.             //
  6472.             // will generate
  6473.             //    Z = x2 x3 y2 y3
  6474.             ////////////////////////////////////////////////////////////////////////////////
  6475.             vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  6476.  
  6477.             ////////////////////////////////////////////////////////////////////////////////
  6478.             // point at top of current columns in matrix
  6479.             ////////////////////////////////////////////////////////////////////////////////
  6480.  
  6481.             pCurrentColumn = (vector float*)data;        
  6482.  
  6483.             ////////////////////////////////////////////////////////////////////////////////
  6484.             // prepare pointers into column buffer to make copies of first two columns of
  6485.             // data (which are real data) and third column, which is complex data. 
  6486.             ////////////////////////////////////////////////////////////////////////////////
  6487.  
  6488.             pSplit1 = *(vector float**)rowBufferHandle;
  6489.             pSplit2 = pSplit1 + height / 4;
  6490.             pSplit3 = pSplit1 + height / 2;
  6491.                 
  6492.             ////////////////////////////////////////////////////////////////////////////////
  6493.             // loop through all rows (four at a time), making copies of the two real 
  6494.             // columns and one complex column.
  6495.             ////////////////////////////////////////////////////////////////////////////////
  6496.  
  6497.             for (j=0; j < height/4; j++) {
  6498.                         
  6499.                 ////////////////////////////////////////////////////////////////////////////////
  6500.                 // read in four rows of data from the columns.
  6501.                 ////////////////////////////////////////////////////////////////////////////////
  6502.  
  6503.                 vIn1 = *pCurrentColumn;
  6504.                 pCurrentColumn += width/4;
  6505.                 vIn2 = *pCurrentColumn;
  6506.                 pCurrentColumn += width/4;
  6507.                 vIn3 = *pCurrentColumn;
  6508.                 pCurrentColumn += width/4;
  6509.                 vIn4 = *pCurrentColumn;
  6510.                 pCurrentColumn += width/4;
  6511.                 
  6512.                 ////////////////////////////////////////////////////////////////////////////////
  6513.                 // create temp vectors that contain real data from first two columns
  6514.                 ////////////////////////////////////////////////////////////////////////////////
  6515.  
  6516.                 vTemp1 = vec_mergeh(vIn1, vIn2);
  6517.                 vTemp2 = vec_mergeh(vIn3, vIn4);
  6518.                 
  6519.                 ////////////////////////////////////////////////////////////////////////////////
  6520.                 // create a vector that contains four entries from first real column
  6521.                 ////////////////////////////////////////////////////////////////////////////////
  6522.                 
  6523.                 vOut1 = vec_perm(vTemp1, vTemp2, vMergeHiPairPerm);
  6524.  
  6525.                 ////////////////////////////////////////////////////////////////////////////////
  6526.                 // create a vector that contains four entries from second real column
  6527.                 ////////////////////////////////////////////////////////////////////////////////
  6528.  
  6529.                 vOut2 = vec_perm(vTemp1, vTemp2, vMergeLoPairPerm);
  6530.  
  6531.                 ////////////////////////////////////////////////////////////////////////////////
  6532.                 // create two vectors that contains four entries from first complex column
  6533.                 ////////////////////////////////////////////////////////////////////////////////
  6534.  
  6535.                 vOut3 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  6536.                 vOut4 = vec_perm(vIn3, vIn4, vMergeLoPairPerm);
  6537.  
  6538.                 ////////////////////////////////////////////////////////////////////////////////
  6539.                 // store our vectors to appropriate temporary buffer location
  6540.                 ////////////////////////////////////////////////////////////////////////////////
  6541.                             
  6542.                 *pSplit1++ = vOut1;
  6543.                 *pSplit2++ = vOut2;
  6544.                 *pSplit3++ = vOut3;
  6545.                 *pSplit3++ = vOut4;
  6546.                 
  6547.             }
  6548.  
  6549.             ////////////////////////////////////////////////////////////////////////////////
  6550.             // perform real fft on copies of first two columns
  6551.             ////////////////////////////////////////////////////////////////////////////////
  6552.  
  6553.             pFFT1 = *(float **)rowBufferHandle;
  6554.             pFFT2 = pFFT1 + height;
  6555.             
  6556.             result =  FFTRealForward(pFFT1, height);
  6557.             if (result == noErr) {
  6558.                 result = FFTRealForward(pFFT2, height);
  6559.             }
  6560.  
  6561.             ////////////////////////////////////////////////////////////////////////////////
  6562.             // perform complex fft on copy of first complex column
  6563.             ////////////////////////////////////////////////////////////////////////////////
  6564.  
  6565.             pFFT2 = pFFT1 + 2*height;
  6566.  
  6567.             if (result == noErr) {
  6568.                 result = FFTComplex(pFFT2, height, -1);
  6569.             }
  6570.             
  6571.             if (result == noErr) {
  6572.  
  6573.                 ////////////////////////////////////////////////////////////////////////////////
  6574.                 // point at beginning of copy buffers to prepare to copy data back into
  6575.                 // columns of matrix after having performed FFTs.
  6576.                 ////////////////////////////////////////////////////////////////////////////////
  6577.                     
  6578.                 pSplit1 = *(vector float**)rowBufferHandle;
  6579.                 pSplit2 = pSplit1 + height / 4;
  6580.                 pSplit3 = pSplit1 + height / 2;
  6581.  
  6582.                 ////////////////////////////////////////////////////////////////////////////////
  6583.                 // point to top of columns that we will be copying back into
  6584.                 ////////////////////////////////////////////////////////////////////////////////
  6585.                 pCurrentColumn = (vector float*)data;
  6586.  
  6587.  
  6588.                 ////////////////////////////////////////////////////////////////////////////////
  6589.                 // loop through all rows (four at a time), copying data from temporary buffer
  6590.                 // back into appropriate row positions in the current columns
  6591.                 ////////////////////////////////////////////////////////////////////////////////
  6592.                 for (j=0; j < height/4; j++) {
  6593.                 
  6594.                     ////////////////////////////////////////////////////////////////////////////////
  6595.                     // get one vector from result of first real fft
  6596.                     ////////////////////////////////////////////////////////////////////////////////
  6597.  
  6598.                     vIn1 = *pSplit1++;
  6599.  
  6600.                     ////////////////////////////////////////////////////////////////////////////////
  6601.                     // get one vector from result of second real fft
  6602.                     ////////////////////////////////////////////////////////////////////////////////
  6603.                     
  6604.                     vIn2 = *pSplit2++;
  6605.  
  6606.                     ////////////////////////////////////////////////////////////////////////////////
  6607.                     // get two vector from result of first complex fft
  6608.                     ////////////////////////////////////////////////////////////////////////////////
  6609.  
  6610.                     vIn3 = *pSplit3++;
  6611.                     vIn4 = *pSplit3++;
  6612.                 
  6613.                     ////////////////////////////////////////////////////////////////////////////////
  6614.                     // permute all data back into columnwise form to be stored as vectors in
  6615.                     // the original matrix
  6616.                     ////////////////////////////////////////////////////////////////////////////////
  6617.  
  6618.                     vTemp1 = vec_mergeh(vIn1, vIn2);    
  6619.                     vTemp2 = vec_mergel(vIn1, vIn2);    
  6620.                     
  6621.                     vOut1 = vec_perm(vTemp1, vIn3, vMergeHiPairPerm);
  6622.                     vOut2 = vec_perm(vTemp1, vIn3, vMergeLoPairPerm);
  6623.                     vOut3 = vec_perm(vTemp2, vIn4, vMergeHiPairPerm);
  6624.                     vOut4 = vec_perm(vTemp2, vIn4, vMergeLoPairPerm);
  6625.  
  6626.                     ////////////////////////////////////////////////////////////////////////////////
  6627.                     // store four vectors of data back into the current columns
  6628.                     ////////////////////////////////////////////////////////////////////////////////
  6629.                                     
  6630.                     *pCurrentColumn = vOut1;
  6631.                     pCurrentColumn += width / 4;
  6632.                     *pCurrentColumn = vOut2;                
  6633.                     pCurrentColumn += width / 4;
  6634.                     *pCurrentColumn = vOut3;                
  6635.                     pCurrentColumn += width / 4;
  6636.                     *pCurrentColumn = vOut4;                
  6637.                     pCurrentColumn += width / 4;
  6638.                                     
  6639.                 }
  6640.                                             
  6641.                 ////////////////////////////////////////////////////////////////////////////////
  6642.                 // we now loop through all remaining columns, two columns at a time, and perform
  6643.                 //  column ferrying FFTs on the columns.  We first copy the columns to a separate
  6644.                 // buffer, then perform the FFTs, and finally copy them back to their original
  6645.                 // column positions.
  6646.                 ////////////////////////////////////////////////////////////////////////////////
  6647.  
  6648.                 for (i=1; i<width/4; i++) {
  6649.  
  6650.                     ////////////////////////////////////////////////////////////////////////////////
  6651.                     // point at top of current columns
  6652.                     ////////////////////////////////////////////////////////////////////////////////
  6653.                 
  6654.                     pCurrentColumn = ((vector float*)data) + i;        
  6655.  
  6656.                     ////////////////////////////////////////////////////////////////////////////////
  6657.                     // initialize pointers in temporary buffer for storing copied columns.
  6658.                     ////////////////////////////////////////////////////////////////////////////////
  6659.  
  6660.                     pSplit1 = *(vector float**)rowBufferHandle;
  6661.                     pSplit2 = pSplit1 + height / 2;
  6662.                         
  6663.                     ////////////////////////////////////////////////////////////////////////////////
  6664.                     // loop through all of the column entries that are stored in the temp buffer,
  6665.                     // and merge them to be stored back into the columns of the matrix. 
  6666.                     ////////////////////////////////////////////////////////////////////////////////
  6667.  
  6668.                     for (j=0; j < height/2; j++) {
  6669.  
  6670.                         ////////////////////////////////////////////////////////////////////////////////
  6671.                         // read in two rows worth of vectors (two rows X two columns)
  6672.                         ////////////////////////////////////////////////////////////////////////////////
  6673.                         vIn1 = *pCurrentColumn;
  6674.                         pCurrentColumn += width/4;
  6675.                         vIn2 = *pCurrentColumn;
  6676.                         pCurrentColumn += width/4;
  6677.                         
  6678.                         ////////////////////////////////////////////////////////////////////////////////
  6679.                         // permute the vectors so that the two left column entries are in one vector
  6680.                         // and the two right column entries are in one vector
  6681.                         ////////////////////////////////////////////////////////////////////////////////
  6682.                         vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  6683.                         vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  6684.                         
  6685.                         ////////////////////////////////////////////////////////////////////////////////
  6686.                         // store the split columns to the appropriate buffers
  6687.                         ////////////////////////////////////////////////////////////////////////////////
  6688.                         *pSplit1++ = vOut1;
  6689.                         *pSplit2++ = vOut2;
  6690.  
  6691.                     }
  6692.  
  6693.                     ////////////////////////////////////////////////////////////////////////////////
  6694.                     // perform FFTs on the two columns of data that we have copied to the temp
  6695.                     // buffer
  6696.                     ////////////////////////////////////////////////////////////////////////////////
  6697.  
  6698.                     pFFT1 = *(float **)rowBufferHandle;
  6699.                     pFFT2 = pFFT1 + 2*height;
  6700.                     
  6701.                     result = FFTComplex(pFFT1, height, -1);
  6702.                     if (result != noErr) break;
  6703.                     
  6704.                     result = FFTComplex(pFFT2, height, -1);
  6705.                     if (result != noErr) break;
  6706.                         
  6707.                     ////////////////////////////////////////////////////////////////////////////////
  6708.                     // point at the beginning of the two copied column buffers, and at the top
  6709.                     // of the columns in the matrix where we will store them back.
  6710.                     ////////////////////////////////////////////////////////////////////////////////
  6711.  
  6712.                     pSplit1 = *(vector float**)rowBufferHandle;
  6713.                     pSplit2 = pSplit1 + height / 2;
  6714.                     pCurrentColumn = ((vector float*)data) + i;
  6715.  
  6716.                     ////////////////////////////////////////////////////////////////////////////////
  6717.                     // loop through all of the column entries that are stored in the temp buffer,
  6718.                     // and merge them to be stored back into the columns of the matrix. 
  6719.                     ////////////////////////////////////////////////////////////////////////////////
  6720.                     for (j=0; j < height/2; j++) {
  6721.                     
  6722.                         ////////////////////////////////////////////////////////////////////////////////
  6723.                         // get two vectors of column data
  6724.                         ////////////////////////////////////////////////////////////////////////////////
  6725.  
  6726.                         vIn1 = *pSplit1++;
  6727.                         vIn2 = *pSplit2++;
  6728.                         
  6729.                         ////////////////////////////////////////////////////////////////////////////////
  6730.                         // turn them into row vectors
  6731.                         ////////////////////////////////////////////////////////////////////////////////
  6732.  
  6733.                         vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  6734.                         vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  6735.                                         
  6736.                         ////////////////////////////////////////////////////////////////////////////////
  6737.                         // store row vectors back into the matrix
  6738.                         ////////////////////////////////////////////////////////////////////////////////
  6739.  
  6740.                         *pCurrentColumn = vOut1;
  6741.                         pCurrentColumn += width / 4;
  6742.                         *pCurrentColumn = vOut2;                
  6743.                         pCurrentColumn += width / 4;
  6744.                                         
  6745.                     }        
  6746.                 
  6747.                 }
  6748.             }                
  6749.         }
  6750.                         
  6751.     }
  6752.  
  6753.     if (rowBufferHandle) {
  6754.         DisposeHandle(rowBufferHandle);
  6755.     }
  6756.  
  6757.     return result;
  6758.  
  6759. }
  6760.  
  6761. ////////////////////////////////////////////////////////////////////////////////
  6762. //    FFT2DRealInverse
  6763. //
  6764. //    performs an inverse 2-dimensional FFT on a real 2D (width X height) signal. 
  6765. //     Routine expects input data to be in the following 2D-hermitian form:
  6766. //
  6767. //    X = 
  6768. //        
  6769. //    Xr(0,0)        Xr(0, W/2)        Xr(0,1)    Xi(0,1)    Xr(0,2)    Xi(0,2)    ... Xr(0,W/2-1) Xi(0,W/2-1)
  6770. //    Xr(H/2,0)    Xr(H/2,W/2)        Xr(1,1)    Xi(1,1)    Xr(1,2)    Xi(1,2)    ... Xr(1,W/2-1) Xi(1,W/2-1)
  6771. //    Xr(1,0)        Xr(1,W/2)        Xr(2,1)    Xi(2,1)    Xr(2,2)    Xi(2,2)    ... Xr(2,W/2-1) Xi(2,W/2-1)
  6772. //    Xi(1,0)        Xi(1,W/2)        Xr(3,1)    Xi(3,1)    Xr(3,2)    Xi(3,2)    ... Xr(3,W/2-1) Xi(3,W/2-1)
  6773. //    .
  6774. //    .
  6775. //    .
  6776. //    Xr(H/2-1,0)    Xr(H/2-1,W/2)    Xr(H-2,1)    Xi(H-2,1)    ...         Xr(H-2,W/2-1) Xi(H-2,W/2-1)
  6777. //    Xi(H/2-1,0)    Xi(H/2-1,W/2)    Xr(H-1,1)    Xi(H-1,1)    ...         Xr(H-1,W/2-1) Xi(H-1,W/2-1)
  6778. //
  6779. // The inverse real 2D FFT is performed in the following steps.  First, an
  6780. // inverse real FFT is performed on the first two columns.   Then, an inverse
  6781. // complex FFT is performed on the remaining columns of complex numbers.
  6782. // Finally, an inverse real FFT is performed on each row of the matrix, resulting
  6783. // in a width X height all-real signal.
  6784. //
  6785. //    **NOTE** that implementation details demand that width >= 8 and height >=4
  6786. //
  6787. ////////////////////////////////////////////////////////////////////////////////
  6788.  
  6789. OSErr    FFT2DRealInverse(float *data, unsigned long width, unsigned long height)
  6790. {
  6791.     long        i, j;
  6792.     float        *pRow;
  6793.     long        rowPower;
  6794.     long        colPower;
  6795.     Handle        rowBufferHandle = nil;
  6796.     OSErr        result = noErr;
  6797.  
  6798.     ////////////////////////////////////////////////////////////////////////////////
  6799.     // ensure that width & height are at least 4 (required for algorithm impl)
  6800.     ////////////////////////////////////////////////////////////////////////////////
  6801.     if ((width < 8) || (height < 4)) {
  6802.         return paramErr;    
  6803.     }    
  6804.                    
  6805.     rowPower = log2max(width);
  6806.     colPower = log2max(height);
  6807.     
  6808.     
  6809.     ////////////////////////////////////////////////////////////////////////////////
  6810.     // width must be an exact power of 2
  6811.     ////////////////////////////////////////////////////////////////////////////////
  6812.     if ((1 << rowPower) != width) {
  6813.         return paramErr;
  6814.     }
  6815.  
  6816.     ////////////////////////////////////////////////////////////////////////////////
  6817.     // height must be an exact power of 2
  6818.     ////////////////////////////////////////////////////////////////////////////////
  6819.     if ((1 << colPower) != height) {
  6820.         return paramErr;
  6821.     }
  6822.     
  6823.     ////////////////////////////////////////////////////////////////////////////////
  6824.     // allocate a buffer for column ferrying of two columns.
  6825.     ////////////////////////////////////////////////////////////////////////////////
  6826.  
  6827.     rowBufferHandle = NewHandle(2*2*sizeof(float)*height);
  6828.     
  6829.     result = MemError();
  6830.     
  6831.     if (result == noErr) {
  6832.         vector float            *pCurrentColumn;
  6833.         vector float            vIn1, vIn2, vIn3, vIn4;
  6834.         vector float            vOut1, vOut2, vOut3, vOut4;
  6835.         vector unsigned char    vMergeHiPairPerm;
  6836.         vector unsigned char    vMergeLoPairPerm;
  6837.         vector float            *pSplit1, *pSplit2, *pSplit3;
  6838.         float                    *pFFT1, *pFFT2;
  6839.         vector float            vTemp1, vTemp2;        
  6840.         
  6841.         
  6842.         ////////////////////////////////////////////////////////////////////////////////
  6843.         // initialize a permute vector that, given input vectors:
  6844.         //
  6845.         //    X = x0 x1 x2 x3
  6846.         //    Y = y0 y1 y2 y3
  6847.         //
  6848.         // will generate
  6849.         //    Z = x0 x1 y0 y1
  6850.         ////////////////////////////////////////////////////////////////////////////////
  6851.         vMergeHiPairPerm = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23);
  6852.  
  6853.         ////////////////////////////////////////////////////////////////////////////////
  6854.         // initialize a permute vector that, given input vectors:
  6855.         //
  6856.         //    X = x0 x1 x2 x3
  6857.         //    Y = y0 y1 y2 y3
  6858.         //
  6859.         // will generate
  6860.         //    Z = x2 x3 y2 y3
  6861.         ////////////////////////////////////////////////////////////////////////////////
  6862.         vMergeLoPairPerm = (vector unsigned char)(8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31);
  6863.  
  6864.         ////////////////////////////////////////////////////////////////////////////////
  6865.         // point at top of current columns in matrix
  6866.         ////////////////////////////////////////////////////////////////////////////////
  6867.  
  6868.         pCurrentColumn = (vector float*)data;        
  6869.  
  6870.         ////////////////////////////////////////////////////////////////////////////////
  6871.         // prepare pointers into column buffer to make copies of first two columns of
  6872.         // data (which are complex data stored vertically) and third column, 
  6873.         // (which is complex data stored two-wide).
  6874.         ////////////////////////////////////////////////////////////////////////////////
  6875.  
  6876.         pSplit1 = *(vector float**)rowBufferHandle;
  6877.         pSplit2 = pSplit1 + height / 4;
  6878.         pSplit3 = pSplit1 + height / 2;
  6879.             
  6880.         ////////////////////////////////////////////////////////////////////////////////
  6881.         // loop through all rows (four at a time), making copies of the two narrow
  6882.         // columns and one wide column.
  6883.         ////////////////////////////////////////////////////////////////////////////////
  6884.  
  6885.         for (j=0; j < height/4; j++) {
  6886.                     
  6887.             ////////////////////////////////////////////////////////////////////////////////
  6888.             // read in four rows of data from the columns.
  6889.             ////////////////////////////////////////////////////////////////////////////////
  6890.             vIn1 = *pCurrentColumn;
  6891.             pCurrentColumn += width/4;
  6892.             vIn2 = *pCurrentColumn;
  6893.             pCurrentColumn += width/4;
  6894.             vIn3 = *pCurrentColumn;
  6895.             pCurrentColumn += width/4;
  6896.             vIn4 = *pCurrentColumn;
  6897.             pCurrentColumn += width/4;
  6898.             
  6899.             
  6900.             ////////////////////////////////////////////////////////////////////////////////
  6901.             // permute input data so that we have one vector that contains all data of
  6902.             // first column, one vector that contains all data of second column, and two
  6903.             // vectors that contain all data of third column.
  6904.             ////////////////////////////////////////////////////////////////////////////////
  6905.  
  6906.             vTemp1 = vec_mergeh(vIn1, vIn2);
  6907.             vTemp2 = vec_mergeh(vIn3, vIn4);
  6908.             
  6909.             vOut1 = vec_perm(vTemp1, vTemp2, vMergeHiPairPerm);
  6910.             vOut2 = vec_perm(vTemp1, vTemp2, vMergeLoPairPerm);
  6911.             vOut3 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  6912.             vOut4 = vec_perm(vIn3, vIn4, vMergeLoPairPerm);
  6913.  
  6914.             ////////////////////////////////////////////////////////////////////////////////
  6915.             // store our column data vectors to the appropriate buffers
  6916.             ////////////////////////////////////////////////////////////////////////////////
  6917.                         
  6918.             *pSplit1++ = vOut1;
  6919.             *pSplit2++ = vOut2;
  6920.             *pSplit3++ = vOut3;
  6921.             *pSplit3++ = vOut4;
  6922.         }
  6923.  
  6924.         ////////////////////////////////////////////////////////////////////////////////
  6925.         // perform real inverse FFTs on first two columns.
  6926.         ////////////////////////////////////////////////////////////////////////////////
  6927.  
  6928.         pFFT1 = *(float **)rowBufferHandle;
  6929.         pFFT2 = pFFT1 + height;
  6930.         
  6931.         result = FFTRealInverse(pFFT1, height);
  6932.         if (result == noErr) {
  6933.             result = FFTRealInverse(pFFT2, height);
  6934.         }
  6935.  
  6936.         ////////////////////////////////////////////////////////////////////////////////
  6937.         // perform complex inverse FFT on first complex column
  6938.         ////////////////////////////////////////////////////////////////////////////////
  6939.         pFFT2 = pFFT1 + 2*height;
  6940.  
  6941.         if (result == noErr) {
  6942.             result = FFTComplex(pFFT2, height, 1);
  6943.         }
  6944.         
  6945.         if (result == noErr) {    
  6946.  
  6947.             ////////////////////////////////////////////////////////////////////////////////
  6948.             // point at beginning of copy buffers to prepare to copy data back into
  6949.             // columns of matrix after having performed inverse FFTs.
  6950.             ////////////////////////////////////////////////////////////////////////////////
  6951.             pSplit1 = *(vector float**)rowBufferHandle;
  6952.             pSplit2 = pSplit1 + height / 4;
  6953.             pSplit3 = pSplit1 + height / 2;
  6954.  
  6955.             ////////////////////////////////////////////////////////////////////////////////
  6956.             // point to top of columns that we will be copying back into
  6957.             ////////////////////////////////////////////////////////////////////////////////
  6958.             pCurrentColumn = (vector float*)data;
  6959.  
  6960.             ////////////////////////////////////////////////////////////////////////////////
  6961.             // loop through all rows (four at a time), copying data from temporary buffer
  6962.             // back into appropriate row positions in the current columns
  6963.             ////////////////////////////////////////////////////////////////////////////////
  6964.             for (j=0; j < height/4; j++) {
  6965.             
  6966.                 ////////////////////////////////////////////////////////////////////////////////
  6967.                 // get one vector of real data from first column
  6968.                 ////////////////////////////////////////////////////////////////////////////////
  6969.             
  6970.                 vIn1 = *pSplit1++;
  6971.  
  6972.                 ////////////////////////////////////////////////////////////////////////////////
  6973.                 // get one vector of real data from second column
  6974.                 ////////////////////////////////////////////////////////////////////////////////
  6975.  
  6976.                 vIn2 = *pSplit2++;
  6977.  
  6978.                 ////////////////////////////////////////////////////////////////////////////////
  6979.                 // get two vectors of real data from second column
  6980.                 ////////////////////////////////////////////////////////////////////////////////
  6981.  
  6982.                 vIn3 = *pSplit3++;
  6983.                 vIn4 = *pSplit3++;
  6984.             
  6985.                 ////////////////////////////////////////////////////////////////////////////////
  6986.                 // permute all data back into columnwise form to be stored as vectors in
  6987.                 // the original matrix
  6988.                 ////////////////////////////////////////////////////////////////////////////////
  6989.  
  6990.                 vTemp1 = vec_mergeh(vIn1, vIn2);    
  6991.                 vTemp2 = vec_mergel(vIn1, vIn2);    
  6992.                 
  6993.                 vOut1 = vec_perm(vTemp1, vIn3, vMergeHiPairPerm);
  6994.                 vOut2 = vec_perm(vTemp1, vIn3, vMergeLoPairPerm);
  6995.                 vOut3 = vec_perm(vTemp2, vIn4, vMergeHiPairPerm);
  6996.                 vOut4 = vec_perm(vTemp2, vIn4, vMergeLoPairPerm);
  6997.                                 
  6998.                 ////////////////////////////////////////////////////////////////////////////////
  6999.                 // store four vectors of data back into the current columns
  7000.                 ////////////////////////////////////////////////////////////////////////////////
  7001.  
  7002.                 *pCurrentColumn = vOut1;
  7003.                 pCurrentColumn += width / 4;
  7004.                 *pCurrentColumn = vOut2;                
  7005.                 pCurrentColumn += width / 4;
  7006.                 *pCurrentColumn = vOut3;                
  7007.                 pCurrentColumn += width / 4;
  7008.                 *pCurrentColumn = vOut4;                
  7009.                 pCurrentColumn += width / 4;
  7010.                                 
  7011.             }
  7012.                                         
  7013.             ////////////////////////////////////////////////////////////////////////////////
  7014.             // we now loop through all remaining columns, two columns at a time, and perform
  7015.             //  column ferrying inverse FFTs on the columns.  We first copy the columns to a
  7016.             //  separate buffer, then perform the FFTs, and finally copy them back to their
  7017.             // original column positions.
  7018.             ////////////////////////////////////////////////////////////////////////////////
  7019.             for (i=1; i<width/4; i++) {
  7020.             
  7021.                 ////////////////////////////////////////////////////////////////////////////////
  7022.                 // point at top of current columns
  7023.                 ////////////////////////////////////////////////////////////////////////////////
  7024.  
  7025.                 pCurrentColumn = ((vector float*)data) + i;        
  7026.  
  7027.                 ////////////////////////////////////////////////////////////////////////////////
  7028.                 // initialize pointers in temporary buffer for storing copied columns.
  7029.                 ////////////////////////////////////////////////////////////////////////////////
  7030.  
  7031.                 pSplit1 = *(vector float**)rowBufferHandle;
  7032.                 pSplit2 = pSplit1 + height / 2;
  7033.                     
  7034.                 ////////////////////////////////////////////////////////////////////////////////
  7035.                 // loop through all of the column entries that are stored in the temp buffer,
  7036.                 // and merge them to be stored back into the columns of the matrix. 
  7037.                 ////////////////////////////////////////////////////////////////////////////////
  7038.  
  7039.                 for (j=0; j < height/2; j++) {
  7040.                 
  7041.                     ////////////////////////////////////////////////////////////////////////////////
  7042.                     // read in two rows worth of vectors (two rows X two columns)
  7043.                     ////////////////////////////////////////////////////////////////////////////////
  7044.                     vIn1 = *pCurrentColumn;
  7045.                     pCurrentColumn += width/4;
  7046.                     vIn2 = *pCurrentColumn;
  7047.                     pCurrentColumn += width/4;
  7048.                     
  7049.                     ////////////////////////////////////////////////////////////////////////////////
  7050.                     // permute the vectors so that the two left column entries are in one vector
  7051.                     // and the two right column entries are in one vector
  7052.                     ////////////////////////////////////////////////////////////////////////////////
  7053.                     vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  7054.                     vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  7055.                     
  7056.                     ////////////////////////////////////////////////////////////////////////////////
  7057.                     // store the split columns to the appropriate buffers
  7058.                     ////////////////////////////////////////////////////////////////////////////////
  7059.                     *pSplit1++ = vOut1;
  7060.                     *pSplit2++ = vOut2;
  7061.                     
  7062.                 }
  7063.  
  7064.                 ////////////////////////////////////////////////////////////////////////////////
  7065.                 // perform inverse FFTs on the two columns of data that we have copied to the 
  7066.                 // temp buffer
  7067.                 ////////////////////////////////////////////////////////////////////////////////
  7068.  
  7069.                 pFFT1 = *(float **)rowBufferHandle;
  7070.                 pFFT2 = pFFT1 + 2*height;
  7071.                 
  7072.                 result = FFTComplex(pFFT1, height, 1);
  7073.                 if (result != noErr) break;
  7074.  
  7075.                 result = FFTComplex(pFFT2, height, 1);
  7076.                 if (result != noErr) break;
  7077.                                     
  7078.                 ////////////////////////////////////////////////////////////////////////////////
  7079.                 // point at the beginning of the two copied column buffers, and at the top
  7080.                 // of the columns in the matrix where we will store them back.
  7081.                 ////////////////////////////////////////////////////////////////////////////////
  7082.  
  7083.                 pSplit1 = *(vector float**)rowBufferHandle;
  7084.                 pSplit2 = pSplit1 + height / 2;
  7085.                 pCurrentColumn = ((vector float*)data) + i;
  7086.  
  7087.                 ////////////////////////////////////////////////////////////////////////////////
  7088.                 // loop through all of the column entries that are stored in the temp buffer,
  7089.                 // and merge them to be stored back into the columns of the matrix. 
  7090.                 ////////////////////////////////////////////////////////////////////////////////
  7091.  
  7092.                 for (j=0; j < height/2; j++) {
  7093.         
  7094.                     ////////////////////////////////////////////////////////////////////////////////
  7095.                     // get two vectors of column data
  7096.                     ////////////////////////////////////////////////////////////////////////////////
  7097.  
  7098.                     vIn1 = *pSplit1++;
  7099.                     vIn2 = *pSplit2++;
  7100.                     
  7101.                     ////////////////////////////////////////////////////////////////////////////////
  7102.                     // turn them into row vectors
  7103.                     ////////////////////////////////////////////////////////////////////////////////
  7104.  
  7105.                     vOut1 = vec_perm(vIn1, vIn2, vMergeHiPairPerm);
  7106.                     vOut2 = vec_perm(vIn1, vIn2, vMergeLoPairPerm);
  7107.                                     
  7108.                     ////////////////////////////////////////////////////////////////////////////////
  7109.                     // store row vectors back into the matrix
  7110.                     ////////////////////////////////////////////////////////////////////////////////
  7111.  
  7112.                     *pCurrentColumn = vOut1;
  7113.                     pCurrentColumn += width / 4;
  7114.                     *pCurrentColumn = vOut2;                
  7115.                     pCurrentColumn += width / 4;
  7116.                                     
  7117.                 }        
  7118.             
  7119.             }
  7120.  
  7121.             if (result == noErr) {
  7122.  
  7123.                 ////////////////////////////////////////////////////////////////////////////////
  7124.                 // perform an inverse real FFT on every row of the matrix
  7125.                 ////////////////////////////////////////////////////////////////////////////////
  7126.             
  7127.                 pRow = data;
  7128.                 
  7129.                 for (i=0; i<height; i++) {
  7130.                     result = FFTRealInverse(pRow+i*(width), width);
  7131.                     if (result != noErr) break;
  7132.                 }
  7133.  
  7134.             }
  7135.         }                
  7136.                 
  7137.     }
  7138.  
  7139.     if (rowBufferHandle) {
  7140.         DisposeHandle(rowBufferHandle);
  7141.     }
  7142.  
  7143.     return result;
  7144.  
  7145. }
  7146.  
  7147. #pragma mark -
  7148. #pragma mark 2 D   C O N V O L U T I O N
  7149.  
  7150. ////////////////////////////////////////////////////////////////////////////////
  7151. //    ConvolveComplexAltivec2D
  7152. //
  7153. //    calculates the 2D convolution of signal1 and signal2.  This is done by
  7154. // performing an FFT on signal1 and signal2, calculating the dyadic product
  7155. // of the two results, and then performing an inverse FFT on the result of
  7156. // the dyadic mul.
  7157. //
  7158. //    signal2 is replaced by the convolution of signal1 and signal2. signal1
  7159. // is replaced by the FFT of signal1.
  7160. //
  7161. ////////////////////////////////////////////////////////////////////////////////
  7162. OSErr ConvolveComplexAltivec2D(float *pSignal1, float *pSignal2, long     width, long    height)
  7163. {    
  7164.     OSErr        result = noErr;
  7165.     
  7166.     ////////////////////////////////////////////////////////////////////////////////
  7167.     // perform 2D FFT on signal 1
  7168.     ////////////////////////////////////////////////////////////////////////////////
  7169.  
  7170.     result = FFT2DComplex(pSignal1, width, height, -1);
  7171.     
  7172.     if (result == noErr) {
  7173.     
  7174.         ////////////////////////////////////////////////////////////////////////////////
  7175.         // perform 2D FFT on signal 1
  7176.         ////////////////////////////////////////////////////////////////////////////////
  7177.         
  7178.         result = FFT2DComplex(pSignal2, width, height, -1);
  7179.         
  7180.         if (result == noErr) {
  7181.             ////////////////////////////////////////////////////////////////////////////////
  7182.             // perform dyadic mul on two signals.  The fact that they are 2D is irrelevant
  7183.             // for the sake of the dyadic mul, so we call the standard dyadic mul for the
  7184.             // entire width*length signal.
  7185.             ////////////////////////////////////////////////////////////////////////////////
  7186.  
  7187.             mul_dyadic_complex_altivec(pSignal1, pSignal2, width*height);    
  7188.         }
  7189.     
  7190.         ////////////////////////////////////////////////////////////////////////////////
  7191.         // perform inverse 2D fft on result in signal2, producing the convolution
  7192.         // of signal1 and signal2
  7193.         ////////////////////////////////////////////////////////////////////////////////
  7194.  
  7195.         result = FFT2DComplex(pSignal2, width, height, 1);
  7196.     }
  7197.     
  7198.     return result;
  7199. }
  7200.  
  7201.  
  7202. ////////////////////////////////////////////////////////////////////////////////
  7203. //    mul_dyadic_2D_hermitian_altivec
  7204. //
  7205. //    Performs a dyadic multiply on the 2D hermitian-order data from
  7206. // a real 2D FFT.  The data for both signals is expected to be in the following
  7207. // 2D hermitian order:
  7208. //
  7209. //    X = 
  7210. //        
  7211. //    Xr(0,0)        Xr(0, W/2)        Xr(0,1)    Xi(0,1)    Xr(0,2)    Xi(0,2)    ... Xr(0,W/2-1) Xi(0,W/2-1)
  7212. //    Xr(H/2,0)    Xr(H/2,W/2)        Xr(1,1)    Xi(1,1)    Xr(1,2)    Xi(1,2)    ... Xr(1,W/2-1) Xi(1,W/2-1)
  7213. //    Xr(1,0)        Xr(1,W/2)        Xr(2,1)    Xi(2,1)    Xr(2,2)    Xi(2,2)    ... Xr(2,W/2-1) Xi(2,W/2-1)
  7214. //    Xi(1,0)        Xi(1,W/2)        Xr(3,1)    Xi(3,1)    Xr(3,2)    Xi(3,2)    ... Xr(3,W/2-1) Xi(3,W/2-1)
  7215. //    .
  7216. //    .
  7217. //    .
  7218. //    Xr(H/2-1,0)    Xr(H/2-1,W/2)    Xr(H-2,1)    Xi(H-2,1)    ...         Xr(H-2,W/2-1) Xi(H-2,W/2-1)
  7219. //    Xi(H/2-1,0)    Xi(H/2-1,W/2)    Xr(H-1,1)    Xi(H-1,1)    ...         Xr(H-1,W/2-1) Xi(H-1,W/2-1)
  7220. //
  7221. //    Signal2 is replaced by Signal2 X Signal1.  Signal1 is unmodified.
  7222. //
  7223. //    **NOTE** that implementation details demand that width >= 8 and height >=4
  7224. //    
  7225. ////////////////////////////////////////////////////////////////////////////////
  7226. static void mul_dyadic_2D_hermitian_altivec(
  7227.             float *pSignal1,
  7228.             float *pSignal2,
  7229.             int   width,
  7230.             int height)
  7231. {
  7232.     vector unsigned char         vSwappedPerm;
  7233.     vector float                vSignal1InTop, vSignal2InTop;
  7234.     vector float                vSignal1InBottom, vSignal2InBottom;
  7235.     vector float                *pSignal1Top, *pSignal2Top;
  7236.     vector float                *pSignal1Bottom, *pSignal2Bottom;
  7237.     vector float                vSignal2OutTop, vSignal2OutBottom;
  7238.     long                        i, j;    
  7239.     vector float                vMul1, vMul2, vMul3, vMul4, vMul5, vMul6;
  7240.     vector unsigned char        vRealsPerm;
  7241.     vector unsigned char        vImsPerm;
  7242.     vector unsigned char        vSwappedNegatePerm;
  7243.     vector float                vNegSignal2Top, vNegSignal2Bottom;
  7244.     vector float                vZero = (vector float)(0);
  7245.     vector unsigned char        vMulPerm1, vMulPerm2, vMulPerm3, vMulPerm4, vMulPerm6;
  7246.     vector float                vNegSignalMultiplier;
  7247.     float                         real1, real2;
  7248.     float                        im1, im2;
  7249.     float                         tempreal, tempim;
  7250.  
  7251.     ////////////////////////////////////////////////////////////////////////////////
  7252.     // initialize a multiplier vector that negates elements 1, 2, and 4 in a
  7253.     // float vector
  7254.     ////////////////////////////////////////////////////////////////////////////////
  7255.     vNegSignalMultiplier = (vector float)(-1, -1, 1, -1);
  7256.     
  7257.     ////////////////////////////////////////////////////////////////////////////////
  7258.     // initialize a permute vector that, given input vectors:
  7259.     //
  7260.     //    X = x0 x1 x2 x3
  7261.     //    Y = y0 y1 y2 y3
  7262.     //
  7263.     // will generate
  7264.     //    Z = x0 x1 x2 x2
  7265.     ////////////////////////////////////////////////////////////////////////////////
  7266.     vMulPerm1  = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 8, 9, 10, 11);
  7267.  
  7268.     ////////////////////////////////////////////////////////////////////////////////
  7269.     // initialize a permute vector that, given input vectors:
  7270.     //
  7271.     //    X = x0 x1 x2 x3
  7272.     //    Y = y0 y1 y2 y3
  7273.     //
  7274.     // will generate
  7275.     //    Z = x0 x1 y3 y3
  7276.     ////////////////////////////////////////////////////////////////////////////////
  7277.     vMulPerm2  = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 28, 29, 30, 31, 28, 29, 30, 31);
  7278.  
  7279.     ////////////////////////////////////////////////////////////////////////////////
  7280.     // initialize a permute vector that, given input vectors:
  7281.     //
  7282.     //    X = x0 x1 x2 x3
  7283.     //    Y = y0 y1 y2 y3
  7284.     //
  7285.     // will generate
  7286.     //    Z = x0 x1 y3 y2
  7287.     ////////////////////////////////////////////////////////////////////////////////
  7288.     vMulPerm3  = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 28, 29, 30, 31, 24, 25, 26, 27);
  7289.  
  7290.     ////////////////////////////////////////////////////////////////////////////////
  7291.     // initialize a permute vector that, given input vectors:
  7292.     //
  7293.     //    X = x0 x1 x2 x3
  7294.     //    Y = y0 y1 y2 y3
  7295.     //
  7296.     // will generate
  7297.     //    Z = x0 x1 y2 y2
  7298.     ////////////////////////////////////////////////////////////////////////////////
  7299.     vMulPerm4  = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 24, 25, 26, 27, 24, 25, 26, 27);
  7300.  
  7301.     ////////////////////////////////////////////////////////////////////////////////
  7302.     // initialize a permute vector that, given input vectors:
  7303.     //
  7304.     //    X = x0 x1 x2 x3
  7305.     //    Y = y0 y1 y2 y3
  7306.     //
  7307.     // will generate
  7308.     //    Z = x0 x1 x3 x3
  7309.     ////////////////////////////////////////////////////////////////////////////////
  7310.     vMulPerm6  = (vector unsigned char)(0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 12, 13, 14, 15);
  7311.  
  7312.                 
  7313.     ////////////////////////////////////////////////////////////////////////////////
  7314.     // initialize a permute vector that, given input vectors:
  7315.     //
  7316.     //    X = x0 x1 x2 x3
  7317.     //    Y = y0 y1 y2 y3
  7318.     //
  7319.     // will generate
  7320.     //    Z = x1 x0 x3 y2
  7321.     ////////////////////////////////////////////////////////////////////////////////
  7322.     vSwappedPerm  = (vector unsigned char)(4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
  7323.  
  7324.     ////////////////////////////////////////////////////////////////////////////////
  7325.     // initialize a permute vector that, given input vectors:
  7326.     //
  7327.     //    X = x0 x1 x2 x3
  7328.     //    Y = y0 y1 y2 y3
  7329.     //
  7330.     // will generate
  7331.     //    Z = x0 x0 x2 x2
  7332.     ////////////////////////////////////////////////////////////////////////////////
  7333.     vRealsPerm  = (vector unsigned char)(0, 1, 2, 3, 0, 1, 2, 3, 8, 9, 10, 11, 8, 9, 10, 11);
  7334.  
  7335.     ////////////////////////////////////////////////////////////////////////////////
  7336.     // initialize a permute vector that, given input vectors:
  7337.     //
  7338.     //    X = x0 x1 x2 x3
  7339.     //    Y = y0 y1 y2 y3
  7340.     //
  7341.     // will generate
  7342.     //    Z = x1 x1 x3 x3
  7343.     ////////////////////////////////////////////////////////////////////////////////
  7344.     vImsPerm  = (vector unsigned char)(4, 5, 6, 7, 4, 5, 6, 7, 12, 13, 14, 15, 12, 13, 14, 15);
  7345.  
  7346.     ////////////////////////////////////////////////////////////////////////////////
  7347.     // initialize a permute vector that, given input vectors:
  7348.     //
  7349.     //    X = x0 x1 x2 x3
  7350.     //    Y = y0 y1 y2 y3
  7351.     //
  7352.     // will generate
  7353.     //    Z = y1 x0 y3 x2
  7354.     ////////////////////////////////////////////////////////////////////////////////
  7355.     vSwappedNegatePerm  = (vector unsigned char)(20, 21, 22, 23, 0, 1, 2, 3, 28, 29, 30, 31, 8, 9, 10, 11);
  7356.  
  7357.  
  7358.     ////////////////////////////////////////////////////////////////////////////////
  7359.     // handle the upper left quad, which are real values (unlike the rest of the
  7360.     // 2D array, which is all complex data).
  7361.     ////////////////////////////////////////////////////////////////////////////////
  7362.     
  7363.     pSignal2[0] *= pSignal1[0];
  7364.     pSignal2[1] *= pSignal1[1];
  7365.     pSignal2[width] *= pSignal1[width];
  7366.     pSignal2[width+1] *= pSignal1[width+1];
  7367.  
  7368.     ////////////////////////////////////////////////////////////////////////////////
  7369.     // calculate first complex of first and second rows, since these elements are
  7370.     // not vector aligned.
  7371.     ////////////////////////////////////////////////////////////////////////////////
  7372.     
  7373.     real1    = pSignal1[2];
  7374.     real2     = pSignal2[2];
  7375.     im1     = pSignal1[3];
  7376.     im2     = pSignal2[3];
  7377.     
  7378.     tempreal    = (real1*real2) - (im1*im2);
  7379.     tempim     = (real1*im2) + (real2*im1);
  7380.     
  7381.     pSignal2[2] = tempreal;
  7382.     pSignal2[3] = tempim;
  7383.  
  7384.     real1    = pSignal1[width+2];
  7385.     real2     = pSignal2[width+2];
  7386.     im1     = pSignal1[width+3];
  7387.     im2     = pSignal2[width+3];
  7388.     
  7389.     tempreal    = (real1*real2) - (im1*im2);
  7390.     tempim     = (real1*im2) + (real2*im1);
  7391.     
  7392.     pSignal2[width+2] = tempreal;
  7393.     pSignal2[width+3] = tempim;
  7394.  
  7395.     ////////////////////////////////////////////////////////////////////////////////
  7396.     // do all of leftmost three columns below upper-left quad.  All columns are
  7397.     // complex, but the first two are single-width, with alternating real and complex
  7398.     // values on each row.  The third column (and all others after it) is double-
  7399.     // width, so that each row contains a real and imaginary value (so the row is
  7400.     // two floats wide).  We have to permute these vectors to create the appropriate
  7401.     // multiplicand vectors for mul-add operations.
  7402.     //
  7403.     //    as we read them in, the vectors are in the following format:
  7404.     //
  7405.     //    vSignal1InTop =     (X1r X2r X3r X3i)
  7406.     //    vSignal1InBottom =     (X1i X2i X4r X4i)
  7407.     //
  7408.     //    vSignal2InTop =     (Y1r Y2r Y3r Y3i)
  7409.     //    vSignal2InBottom =     (Y1i Y2i Y4r Y4i)
  7410.     //
  7411.     //
  7412.     //    We need to generate output vectors in the form:
  7413.     //
  7414.     //    vSignal2OutTop =     (X1r*Y1r - X1i*Y1i, X2r*Y2r - X2i*Y2i, X3r*Y3r - X3i*Y3i, X3r*Y3i + X3i * Y3r);
  7415.     //    vSignal2OutBottom =    (X1r*Y1i + X1i*Y1r, X2r*Y2i + X2i*Y2r, X4r*Y4r - X4i*Y4i, X4r*Y4i + X4i * Y4r);
  7416.     //
  7417.     ////////////////////////////////////////////////////////////////////////////////
  7418.  
  7419.     ////////////////////////////////////////////////////////////////////////////////
  7420.     // point to top two rows of signal 1
  7421.     ////////////////////////////////////////////////////////////////////////////////
  7422.     pSignal1Top = (vector float*)pSignal1+width/2;
  7423.     pSignal1Bottom = pSignal1Top + width/4;
  7424.  
  7425.     ////////////////////////////////////////////////////////////////////////////////
  7426.     // point to top two rows of signal 2
  7427.     ////////////////////////////////////////////////////////////////////////////////
  7428.     pSignal2Top = (vector float*)pSignal2 + width/2;
  7429.     pSignal2Bottom = pSignal2Top + width/4;
  7430.  
  7431.     ////////////////////////////////////////////////////////////////////////////////
  7432.     // loop through all rows, two rows at a time
  7433.     ////////////////////////////////////////////////////////////////////////////////
  7434.  
  7435.     for (i=1; i<height/2; i++) {
  7436.     
  7437.         ////////////////////////////////////////////////////////////////////////////////
  7438.         // load two vectors from next two rows of signal 1
  7439.         ////////////////////////////////////////////////////////////////////////////////
  7440.  
  7441.         vSignal1InTop = *pSignal1Top;
  7442.         vSignal1InBottom = *pSignal1Bottom;
  7443.  
  7444.         ////////////////////////////////////////////////////////////////////////////////
  7445.         // load two vectors from next two rows of signal 2
  7446.         ////////////////////////////////////////////////////////////////////////////////
  7447.  
  7448.         vSignal2InTop = *pSignal2Top;
  7449.         vSignal2InBottom = *pSignal2Bottom;
  7450.         
  7451.         ////////////////////////////////////////////////////////////////////////////////
  7452.         // make negative copies of signal 2 vectors, so that we can use them as
  7453.         // permute arguments to create multiplicand vectors that can be used in 
  7454.         // subsequent mul-add vector ops with the correct signs
  7455.         ////////////////////////////////////////////////////////////////////////////////
  7456.         
  7457.         vNegSignal2Top = vec_madd(vSignal2InTop, vNegSignalMultiplier, vZero);
  7458.         vNegSignal2Bottom = vec_madd(vSignal2InBottom, vNegSignalMultiplier, vZero);
  7459.  
  7460.         ////////////////////////////////////////////////////////////////////////////////
  7461.         //     create multiplicand vectors for mul-add operations
  7462.         ////////////////////////////////////////////////////////////////////////////////
  7463.  
  7464.         vMul1 = vec_perm(vSignal1InTop, vSignal1InTop, vMulPerm1);
  7465.         vMul2 = vec_perm(vSignal1InBottom, vSignal1InTop, vMulPerm2);
  7466.         vMul3 = vec_perm(vNegSignal2Bottom, vNegSignal2Top, vMulPerm3);
  7467.  
  7468.         vMul4 = vec_perm(vSignal1InTop, vSignal1InBottom, vMulPerm4);
  7469.         vMul5 = vec_perm(vSignal2InTop, vNegSignal2Bottom, vMulPerm3);
  7470.         vMul6 = vec_perm(vSignal1InBottom, vSignal2InBottom, vMulPerm6);
  7471.  
  7472.         ////////////////////////////////////////////////////////////////////////////////
  7473.         //    calculate dyadic product of two sets of vectors
  7474.         ////////////////////////////////////////////////////////////////////////////////
  7475.  
  7476.         vSignal2OutTop = vec_madd(vMul1, vSignal2InTop, vZero);
  7477.         vSignal2OutTop = vec_madd(vMul2, vMul3, vSignal2OutTop);
  7478.  
  7479.         vSignal2OutBottom = vec_madd(vMul4, vSignal2InBottom, vZero);
  7480.         vSignal2OutBottom = vec_madd(vMul5, vMul6, vSignal2OutBottom);
  7481.         
  7482.         ////////////////////////////////////////////////////////////////////////////////
  7483.         // store dyadic product results to current location in signal2
  7484.         ////////////////////////////////////////////////////////////////////////////////
  7485.  
  7486.         *pSignal2Top = vSignal2OutTop;
  7487.         *pSignal2Bottom = vSignal2OutBottom;
  7488.  
  7489.         ////////////////////////////////////////////////////////////////////////////////
  7490.         // advance pointers to next two rows of signal1 and signal2
  7491.         ////////////////////////////////////////////////////////////////////////////////
  7492.  
  7493.         pSignal1Top    += width/2;
  7494.         pSignal1Bottom    += width/2;
  7495.         pSignal2Top    += width/2;
  7496.         pSignal2Bottom    += width/2;
  7497.         
  7498.     }
  7499.  
  7500.     ////////////////////////////////////////////////////////////////////////////////
  7501.     // calculate dyadic product for remaining columns.  Remaining columns are two-
  7502.     // wide (real an imaginary floats adjacent in memory).  
  7503.     ////////////////////////////////////////////////////////////////////////////////
  7504.     
  7505.     for (j = 1; j<width/4; j++) {  
  7506.     
  7507.         ////////////////////////////////////////////////////////////////////////////////
  7508.         // point to top of current columns in signal1 and signal2
  7509.         ////////////////////////////////////////////////////////////////////////////////
  7510.         
  7511.         pSignal1Top = ((vector float*)pSignal1) + j;
  7512.         pSignal2Top = ((vector float*)pSignal2) + j;
  7513.  
  7514.         ////////////////////////////////////////////////////////////////////////////////
  7515.         // loop through rows, calculating dyadic product of elements in current columns
  7516.         ////////////////////////////////////////////////////////////////////////////////
  7517.  
  7518.         for (i=0; i<height; i++) {
  7519.  
  7520.             ////////////////////////////////////////////////////////////////////////////////
  7521.             // load two complex entries from signal1
  7522.             ////////////////////////////////////////////////////////////////////////////////
  7523.  
  7524.             vSignal1InTop = *pSignal1Top;
  7525.  
  7526.             ////////////////////////////////////////////////////////////////////////////////
  7527.             // load two complex entries from signal2
  7528.             ////////////////////////////////////////////////////////////////////////////////
  7529.  
  7530.             vSignal2InTop = *pSignal2Top;
  7531.                     
  7532.             ////////////////////////////////////////////////////////////////////////////////
  7533.             // negate signal 2, so we have negative values necessary for our multiplies
  7534.             ////////////////////////////////////////////////////////////////////////////////
  7535.  
  7536.             vNegSignal2Top = vec_sub(vZero, vSignal2InTop);
  7537.             
  7538.             ////////////////////////////////////////////////////////////////////////////////
  7539.             // set up multiplicand vectors.  Since we are multiplying complex numbers, we
  7540.             // need to do more than just call a multiply routine.  Given two complex numbers
  7541.             // x = (xr, xi) and y = (yr, yi), then the product z = (zr, zi) = x*y is defined
  7542.             // as:
  7543.             // 
  7544.             //    zr = xr*yr - xi*yi
  7545.             //    zi = xr*yi + xi*yr
  7546.             //
  7547.             // to perform this multiplication, we generate four multiplicand vectors. If we
  7548.             // consider our input vectors X and Y, they each contain two complex numbers:
  7549.             //
  7550.             //    X = (x1r, x1i, x2r, x2i)
  7551.             //    Y = (y1r, y1i, y2r, y2i)
  7552.             //
  7553.             // then we want to generate a new output Z vector:
  7554.             //
  7555.             //    Z = (x1r*y1r - x1i*y1i, x1r*y1i + x1i*y1r, x2r*y2r - x2i*y2i, x2r*y2i + x2i*y2r)
  7556.             //
  7557.             //    So, we need to have multiplicand vectors:
  7558.             //
  7559.             //    M1 =     x1r        x1r        x2r        x2r
  7560.             //    M2 =     x1i        x1i        x2i     x2i
  7561.             //    M3 =    -y1i    y1r        -y2i    y2r
  7562.             //    M4 =     y1r        y1i        y2r        y2i
  7563.             //
  7564.             //    We can then generate our Z vector with a vector mul and a vector mul-add.
  7565.             ////////////////////////////////////////////////////////////////////////////////
  7566.             vMul1 = vec_perm(vSignal1InTop, vSignal1InTop, vRealsPerm);
  7567.             vMul2 = vec_perm(vSignal1InTop, vSignal1InTop, vImsPerm);
  7568.             vMul3 = vec_perm(vSignal2InTop, vNegSignal2Top, vSwappedNegatePerm);
  7569.             
  7570.             vSignal2OutTop = vec_madd(vMul1, vSignal2InTop, vZero);
  7571.             vSignal2OutTop = vec_madd(vMul2, vMul3, vSignal2OutTop);
  7572.             
  7573.             ////////////////////////////////////////////////////////////////////////////////
  7574.             // store product vector back to current position in signal 2
  7575.             ////////////////////////////////////////////////////////////////////////////////
  7576.  
  7577.             *pSignal2Top = vSignal2OutTop;
  7578.             
  7579.             ////////////////////////////////////////////////////////////////////////////////
  7580.             // advance pointers to next rows
  7581.             ////////////////////////////////////////////////////////////////////////////////
  7582.             
  7583.             pSignal1Top    += width/4;
  7584.             pSignal2Top    += width/4;
  7585.             
  7586.         }
  7587.     }
  7588. }
  7589.  
  7590. ////////////////////////////////////////////////////////////////////////////////
  7591. //    ConvolveRealAltivec2D
  7592. //
  7593. //    calculates the convolution of signal1 and signal2, both of which are 2D
  7594. // signals that are width*height in size.
  7595. //
  7596. // This is done by performing a forward 2D FFT on both signals, then calculating
  7597. // the dyadic product of the two resulting signals.  Finally, an inverse 2D FFT is
  7598. // performed on the result of the dyadic mul.
  7599. //
  7600. //    signal2 is replaced by the convolution of signal1 and signal2. signal1
  7601. // is replaced by the 2D FFT of signal1.
  7602. //
  7603. //    **NOTE** that implementation details demand that width >= 8 and height >=4
  7604. //
  7605. ////////////////////////////////////////////////////////////////////////////////
  7606. OSErr ConvolveRealAltivec2D(float *pSignal1, float *pSignal2, long width, long    height)
  7607. {
  7608.     OSErr        result;
  7609.     
  7610.     ////////////////////////////////////////////////////////////////////////////////
  7611.     // because of implementation details, we have these restrictions
  7612.     ////////////////////////////////////////////////////////////////////////////////
  7613.     if ((width < 8) || (height < 4)) {
  7614.         return paramErr;
  7615.     }
  7616.  
  7617.     ////////////////////////////////////////////////////////////////////////////////
  7618.     // perform 2D forward FFt on signal1
  7619.     ////////////////////////////////////////////////////////////////////////////////
  7620.         
  7621.     result = FFT2DRealForward(pSignal1, width, height);    
  7622.     if (result == noErr) {
  7623.     
  7624.         ////////////////////////////////////////////////////////////////////////////////
  7625.         // perform 2D forward FFt on signal2
  7626.         ////////////////////////////////////////////////////////////////////////////////
  7627.     
  7628.         result = FFT2DRealForward(pSignal2, width, height);    
  7629.         
  7630.         if (result == noErr) {
  7631.         
  7632.             ////////////////////////////////////////////////////////////////////////////////
  7633.             // perform 2D forward FFT on signal2
  7634.             ////////////////////////////////////////////////////////////////////////////////
  7635.             
  7636.             mul_dyadic_2D_hermitian_altivec(pSignal1, pSignal2, width, height);
  7637.             
  7638.             result = FFT2DRealInverse(pSignal2, width, height);    
  7639.             
  7640.         }
  7641.         
  7642.     } 
  7643.  
  7644.  
  7645.     return result;
  7646. }
  7647.  
  7648.  
  7649.